XX
This commit is contained in:
Jakub Roztocil 2014-04-24 15:48:01 +02:00
parent 6f28624134
commit 3cb124bba7
13 changed files with 230 additions and 634 deletions

View File

@ -5,10 +5,8 @@ import json
import shutil
import tempfile
from requests.structures import CaseInsensitiveDict
TESTS_ROOT = os.path.abspath(os.path.dirname(__file__))
# HACK: Prepend ../ to PYTHONPATH so that we can import httpie form there.
TESTS_ROOT = os.path.abspath(os.path.dirname(__file__))
sys.path.insert(0, os.path.realpath(os.path.join(TESTS_ROOT, '..')))
from httpie import ExitStatus
from httpie.models import Environment
@ -21,16 +19,23 @@ HTTPBIN_URL = os.environ.get('HTTPBIN_URL',
CRLF = '\r\n'
COLOR = '\x1b['
HTTP_OK = 'HTTP/1.1 200'
OK_COLOR = (
HTTP_OK_COLOR = (
'HTTP\x1b[39m\x1b[38;5;245m/\x1b[39m\x1b'
'[38;5;37m1.1\x1b[39m\x1b[38;5;245m \x1b[39m\x1b[38;5;37m200'
'\x1b[39m\x1b[38;5;245m \x1b[39m\x1b[38;5;136mOK'
)
COLOR = '\x1b['
def httpbin(path):
"""
Return a fully-qualified URL for `path`.
>>> httpbin('/get')
'http://httpbin.org/get'
"""
url = HTTPBIN_URL + path
return url
@ -39,21 +44,17 @@ def mk_config_dir():
return tempfile.mkdtemp(prefix='httpie_test_config_dir_')
class Response(object):
# noinspection PyDefaultArgument
def __init__(self, url, headers={}, status_code=200):
self.url = url
self.headers = CaseInsensitiveDict(headers)
self.status_code = status_code
class TestEnvironment(Environment):
"""
Environment subclass with reasonable defaults suitable for testing.
"""
colors = 0
stdin_isatty = True,
stdout_isatty = True
is_windows = False
_shutil = shutil # we need it in __del__ (would get gc'd)
_shutil = shutil # needed by __del__ (would get gc'd)
def __init__(self, **kwargs):
@ -75,12 +76,41 @@ class TestEnvironment(Environment):
self._shutil.rmtree(self.config_dir)
class BytesResponse(bytes):
stderr = json = exit_status = None
class Response(object):
stderr = None
json = None
exit_status = None
class StrResponse(str):
stderr = json = exit_status = None
class BytesResponse(bytes, Response):
pass
class StrResponse(str, Response):
@property
def json(self):
if not hasattr(self, '_json'):
self._json = None
# De-serialize JSON body if possible.
if COLOR in self:
# Colorized output cannot be parsed.
pass
elif self.strip().startswith('{'):
# Looks like JSON body.
self._json = json.loads(self)
elif self.count('Content-Type:') == 1 and 'application/json' in self:
# Looks like a JSON HTTP message, try to extract its body.
try:
j = self.strip()[self.strip().rindex('\r\n\r\n'):]
except ValueError:
pass
else:
try:
self._json = json.loads(j)
except ValueError:
pass
return self._json
def http(*args, **kwargs):
@ -119,29 +149,11 @@ def http(*args, **kwargs):
stdout.seek(0)
stderr.seek(0)
output = stdout.read()
try:
r = StrResponse(output.decode('utf8'))
except UnicodeDecodeError:
r = BytesResponse(output)
else:
if COLOR not in r:
# De-serialize JSON body if possible.
if r.strip().startswith('{'):
#noinspection PyTypeChecker
r.json = json.loads(r)
elif r.count('Content-Type:') == 1 and 'application/json' in r:
try:
j = r.strip()[r.strip().rindex('\r\n\r\n'):]
except ValueError:
pass
else:
try:
r.json = json.loads(j)
except ValueError:
pass
r.stderr = stderr.read()
r.exit_status = exit_status
@ -150,3 +162,4 @@ def http(*args, **kwargs):
finally:
stdout.close()
stderr.close()

View File

@ -9,13 +9,9 @@ import httpie.input
class AuthTest(TestCase):
def test_basic_auth(self):
r = http(
'--auth=user:password',
'GET',
httpbin('/basic-auth/user/password')
)
r = http('--auth=user:password', 'GET',
httpbin('/basic-auth/user/password'))
assert HTTP_OK in r
assert '"authenticated": true' in r
assert '"user": "user"' in r
@ -24,27 +20,15 @@ class AuthTest(TestCase):
requests.__version__ == '0.13.6',
reason='Redirects with prefetch=False are broken in Requests 0.13.6')
def test_digest_auth(self):
r = http(
'--auth-type=digest',
'--auth=user:password',
'GET',
httpbin('/digest-auth/auth/user/password')
)
r = http('--auth-type=digest', '--auth=user:password', 'GET',
httpbin('/digest-auth/auth/user/password'))
assert HTTP_OK in r
assert r'"authenticated": true' in r
assert r'"user": "user"', r
def test_password_prompt(self):
httpie.input.AuthCredentials._getpass = lambda self, prompt: 'password'
r = http(
'--auth',
'user',
'GET',
httpbin('/basic-auth/user/password')
)
r = http('--auth', 'user', 'GET', httpbin('/basic-auth/user/password'))
assert HTTP_OK in r
assert '"authenticated": true' in r
assert '"user": "user"' in r
@ -52,12 +36,9 @@ class AuthTest(TestCase):
def test_credentials_in_url(self):
url = httpbin('/basic-auth/user/password')
url = 'http://user:password@' + url.split('http://', 1)[1]
r = http(
'GET',
url
)
r = http('GET', url)
assert HTTP_OK in r
assert '"authenticated": true'in r
assert '"authenticated": true' in r
assert '"user": "user"' in r
def test_credentials_in_url_auth_flag_has_priority(self):
@ -65,11 +46,7 @@ class AuthTest(TestCase):
then the ones from -a are used."""
url = httpbin('/basic-auth/user/password')
url = 'http://user:wrong_password@' + url.split('http://', 1)[1]
r = http(
'--auth=user:password',
'GET',
url
)
r = http('--auth=user:password', 'GET', url)
assert HTTP_OK in r
assert '"authenticated": true' in r
assert '"user": "user"' in r

View File

@ -8,7 +8,6 @@ from tests.fixtures import BIN_FILE_PATH, BIN_FILE_CONTENT, BIN_FILE_PATH_ARG
class BinaryRequestDataTest(TestCase):
def test_binary_stdin(self):
with open(BIN_FILE_PATH, 'rb') as stdin:
env = TestEnvironment(
@ -16,47 +15,23 @@ class BinaryRequestDataTest(TestCase):
stdin_isatty=False,
stdout_isatty=False
)
r = http(
'--print=B',
'POST',
httpbin('/post'),
env=env,
)
r = http('--print=B', 'POST', httpbin('/post'), env=env)
assert r == BIN_FILE_CONTENT
def test_binary_file_path(self):
env = TestEnvironment(
stdin_isatty=True,
stdout_isatty=False
)
r = http(
'--print=B',
'POST',
httpbin('/post'),
'@' + BIN_FILE_PATH_ARG,
env=env,
)
env = TestEnvironment(stdin_isatty=True, stdout_isatty=False)
r = http('--print=B', 'POST', httpbin('/post'),
'@' + BIN_FILE_PATH_ARG, env=env, )
assert r == BIN_FILE_CONTENT
def test_binary_file_form(self):
env = TestEnvironment(
stdin_isatty=True,
stdout_isatty=False
)
r = http(
'--print=B',
'--form',
'POST',
httpbin('/post'),
'test@' + BIN_FILE_PATH_ARG,
env=env,
)
env = TestEnvironment(stdin_isatty=True, stdout_isatty=False)
r = http('--print=B', '--form', 'POST', httpbin('/post'),
'test@' + BIN_FILE_PATH_ARG, env=env)
assert bytes(BIN_FILE_CONTENT) in bytes(r)
class BinaryResponseDataTest(TestCase):
url = 'http://www.google.com/favicon.ico'
@property
@ -66,27 +41,16 @@ class BinaryResponseDataTest(TestCase):
return self._bindata
def test_binary_suppresses_when_terminal(self):
r = http(
'GET',
self.url
)
r = http('GET', self.url)
assert BINARY_SUPPRESSED_NOTICE.decode() in r
def test_binary_suppresses_when_not_terminal_but_pretty(self):
r = http(
'--pretty=all',
'GET',
self.url,
env=TestEnvironment(stdin_isatty=True,
stdout_isatty=False)
)
env = TestEnvironment(stdin_isatty=True, stdout_isatty=False)
r = http('--pretty=all', 'GET', self.url,
env=env)
assert BINARY_SUPPRESSED_NOTICE.decode() in r
def test_binary_included_and_correct_when_suitable(self):
r = http(
'GET',
self.url,
env=TestEnvironment(stdin_isatty=True,
stdout_isatty=False)
)
env = TestEnvironment(stdin_isatty=True, stdout_isatty=False)
r = http('GET', self.url, env=env)
assert r == self.bindata

View File

@ -18,7 +18,6 @@ from httpie.cli import parser
class ItemParsingTest(TestCase):
def setUp(self):
self.key_value_type = KeyValueArgType(
*input.SEP_GROUP_ALL_ITEMS
@ -98,57 +97,33 @@ class ItemParsingTest(TestCase):
class QuerystringTest(TestCase):
def test_query_string_params_in_url(self):
r = http(
'--print=Hhb',
'GET',
httpbin('/get?a=1&b=2')
)
r = http('--print=Hhb', 'GET', httpbin('/get?a=1&b=2'))
path = '/get?a=1&b=2'
url = httpbin(path)
assert HTTP_OK in r
assert 'GET %s HTTP/1.1' % path in r
assert '"url": "%s"' % url in r
def test_query_string_params_items(self):
r = http(
'--print=Hhb',
'GET',
httpbin('/get'),
'a==1',
'b==2'
)
r = http('--print=Hhb', 'GET', httpbin('/get'), 'a==1', 'b==2')
path = '/get?a=1&b=2'
url = httpbin(path)
assert HTTP_OK in r
assert 'GET %s HTTP/1.1' % path in r
assert '"url": "%s"' % url in r
def test_query_string_params_in_url_and_items_with_duplicates(self):
r = http(
'--print=Hhb',
'GET',
httpbin('/get?a=1&a=1'),
'a==1',
'a==1',
'b==2',
)
r = http('--print=Hhb', 'GET', httpbin('/get?a=1&a=1'),
'a==1', 'a==1', 'b==2')
path = '/get?a=1&a=1&a=1&a=1&b=2'
url = httpbin(path)
assert HTTP_OK in r
assert 'GET %s HTTP/1.1' % path in r
assert '"url": "%s"' % url in r
class CLIParserTestCase(TestCase):
def test_expand_localhost_shorthand(self):
args = parser.parse_args(args=[':'], env=TestEnvironment())
assert args.url == 'http://localhost'
@ -193,7 +168,6 @@ class CLIParserTestCase(TestCase):
class ArgumentParserTestCase(TestCase):
def setUp(self):
self.parser = input.Parser()
@ -213,7 +187,6 @@ class ArgumentParserTestCase(TestCase):
assert self.parser.args.items == []
def test_guess_when_method_not_set(self):
self.parser.args = argparse.Namespace()
self.parser.args.method = None
self.parser.args.url = 'http://example.com/'
@ -240,9 +213,9 @@ class ArgumentParserTestCase(TestCase):
assert self.parser.args.url == 'http://example.com/'
assert self.parser.args.items == [
KeyValue(key='data',
value='field',
sep='=',
orig='data=field')
value='field',
sep='=',
orig='data=field')
]
def test_guess_when_method_set_but_invalid_and_header_field(self):
@ -260,9 +233,9 @@ class ArgumentParserTestCase(TestCase):
assert self.parser.args.url == 'http://example.com/'
assert self.parser.args.items, [
KeyValue(key='test',
value='header',
sep=':',
orig='test:header')
value='header',
sep=':',
orig='test:header')
]
def test_guess_when_method_set_but_invalid_and_item_exists(self):
@ -287,46 +260,27 @@ class ArgumentParserTestCase(TestCase):
class TestNoOptions(TestCase):
def test_valid_no_options(self):
r = http(
'--verbose',
'--no-verbose',
'GET',
httpbin('/get')
)
r = http('--verbose', '--no-verbose', 'GET', httpbin('/get'))
assert 'GET /get HTTP/1.1' not in r
def test_invalid_no_options(self):
r = http(
'--no-war',
'GET',
httpbin('/get')
)
r = http('--no-war', 'GET', httpbin('/get'))
assert r.exit_status == 1
assert 'unrecognized arguments: --no-war' in r.stderr
assert 'GET /get HTTP/1.1' not in r
class IgnoreStdinTest(TestCase):
def test_ignore_stdin(self):
with open(FILE_PATH) as f:
r = http(
'--ignore-stdin',
'--verbose',
httpbin('/get'),
env=TestEnvironment(stdin=f, stdin_isatty=False)
)
env = TestEnvironment(stdin=f, stdin_isatty=False)
r = http('--ignore-stdin', '--verbose', httpbin('/get'), env=env)
assert HTTP_OK in r
assert 'GET /get HTTP' in r, "Don't default to POST."
assert FILE_CONTENT not in r, "Don't send stdin data."
def test_ignore_stdin_cannot_prompt_password(self):
r = http(
'--ignore-stdin',
'--auth=username-without-password',
httpbin('/get'),
)
r = http('--ignore-stdin', '--auth=no-password', httpbin('/get'))
assert r.exit_status == ExitStatus.ERROR
assert 'because --ignore-stdin' in r.stderr

View File

@ -9,47 +9,29 @@ from tests.fixtures import FILE_PATH
class ImplicitHTTPMethodTest(TestCase):
def test_implicit_GET(self):
r = http(httpbin('/get'))
assert HTTP_OK in r
def test_implicit_GET_with_headers(self):
r = http(
httpbin('/headers'),
'Foo:bar'
)
r = http(httpbin('/headers'), 'Foo:bar')
assert HTTP_OK in r
assert '"Foo": "bar"' in r
def test_implicit_POST_json(self):
r = http(
httpbin('/post'),
'hello=world'
)
r = http(httpbin('/post'), 'hello=world')
assert HTTP_OK in r
assert r'\"hello\": \"world\"' in r
def test_implicit_POST_form(self):
r = http(
'--form',
httpbin('/post'),
'foo=bar'
)
r = http('--form', httpbin('/post'), 'foo=bar')
assert HTTP_OK in r
assert '"foo": "bar"' in r
def test_implicit_POST_stdin(self):
with open(FILE_PATH) as f:
env = TestEnvironment(
stdin_isatty=False,
stdin=f,
)
r = http(
'--form',
httpbin('/post'),
env=env
)
env = TestEnvironment(stdin_isatty=False, stdin=f)
r = http('--form', httpbin('/post'), env=env)
assert HTTP_OK in r
@ -60,53 +42,36 @@ class AutoContentTypeAndAcceptHeadersTest(TestCase):
-f is used.
"""
def test_GET_no_data_no_auto_headers(self):
# https://github.com/jkbr/httpie/issues/62
r = http(
'GET',
httpbin('/headers')
)
r = http('GET', httpbin('/headers'))
assert HTTP_OK in r
assert '"Accept": "*/*"' in r
assert '"Content-Type": "application/json' not in r
def test_POST_no_data_no_auto_headers(self):
# JSON headers shouldn't be automatically set for POST with no data.
r = http(
'POST',
httpbin('/post')
)
r = http('POST', httpbin('/post'))
assert HTTP_OK in r
assert '"Accept": "*/*"' in r
assert '"Content-Type": "application/json' not in r
def test_POST_with_data_auto_JSON_headers(self):
r = http(
'POST',
httpbin('/post'),
'a=b'
)
r = http('POST', httpbin('/post'), 'a=b')
assert HTTP_OK in r
assert '"Accept": "application/json"' in r
assert '"Content-Type": "application/json; charset=utf-8' in r
def test_GET_with_data_auto_JSON_headers(self):
# JSON headers should automatically be set also for GET with data.
r = http(
'POST',
httpbin('/post'),
'a=b'
)
r = http('POST', httpbin('/post'), 'a=b')
assert HTTP_OK in r
assert '"Accept": "application/json"' in r
assert '"Content-Type": "application/json; charset=utf-8' in r
def test_POST_explicit_JSON_auto_JSON_accept(self):
r = http(
'--json',
'POST',
httpbin('/post')
)
r = http('--json', 'POST', httpbin('/post'))
assert HTTP_OK in r
assert r.json['headers']['Accept'] == 'application/json'
# Make sure Content-Type gets set even with no data.
@ -114,57 +79,30 @@ class AutoContentTypeAndAcceptHeadersTest(TestCase):
assert 'application/json' in r.json['headers']['Content-Type']
def test_GET_explicit_JSON_explicit_headers(self):
r = http(
'--json',
'GET',
httpbin('/headers'),
'Accept:application/xml',
'Content-Type:application/xml'
)
r = http('--json', 'GET', httpbin('/headers'),
'Accept:application/xml',
'Content-Type:application/xml')
assert HTTP_OK in r
assert '"Accept": "application/xml"' in r
assert '"Content-Type": "application/xml"' in r
def test_POST_form_auto_Content_Type(self):
r = http(
'--form',
'POST',
httpbin('/post')
)
r = http('--form', 'POST', httpbin('/post'))
assert HTTP_OK in r
assert '"Content-Type": "application/x-www-form-urlencoded' in r
def test_POST_form_Content_Type_override(self):
r = http(
'--form',
'POST',
httpbin('/post'),
'Content-Type:application/xml'
)
r = http('--form', 'POST', httpbin('/post'),
'Content-Type:application/xml')
assert HTTP_OK in r
assert '"Content-Type": "application/xml"' in r
def test_print_only_body_when_stdout_redirected_by_default(self):
r = http(
'GET',
httpbin('/get'),
env=TestEnvironment(
stdin_isatty=True,
stdout_isatty=False
)
)
env = TestEnvironment(stdin_isatty=True, stdout_isatty=False)
r = http('GET', httpbin('/get'), env=env)
assert 'HTTP/' not in r
def test_print_overridable_when_stdout_redirected(self):
r = http(
'--print=h',
'GET',
httpbin('/get'),
env=TestEnvironment(
stdin_isatty=True,
stdout_isatty=False
)
)
env = TestEnvironment(stdin_isatty=True, stdout_isatty=False)
r = http('--print=h', 'GET', httpbin('/get'), env=env)
assert HTTP_OK in r

View File

@ -2,6 +2,8 @@ import os
import time
from unittest import TestCase
from requests.structures import CaseInsensitiveDict
from httpie.compat import urlopen
from httpie.downloads import (
parse_content_range,
@ -11,13 +13,19 @@ from httpie.downloads import (
ContentRangeError,
Download,
)
from tests import httpbin, http, TestEnvironment, Response
from tests import httpbin, http, TestEnvironment
class Response(object):
# noinspection PyDefaultArgument
def __init__(self, url, headers={}, status_code=200):
self.url = url
self.headers = CaseInsensitiveDict(headers)
self.status_code = status_code
class DownloadUtilsTest(TestCase):
def test_Content_Range_parsing(self):
parse = parse_content_range
assert parse('bytes 100-199/200', 100) == 200
@ -73,20 +81,20 @@ class DownloadUtilsTest(TestCase):
)
def test_unique_filename(self):
def make_exists(unique_on_attempt=0):
def attempts(unique_on_attempt=0):
# noinspection PyUnresolvedReferences,PyUnusedLocal
def exists(filename):
if exists.attempt == unique_on_attempt:
return False
exists.attempt += 1
return True
exists.attempt = 0
return exists
assert 'foo.bar' == get_unique_filename('foo.bar', make_exists())
assert 'foo.bar-1' == get_unique_filename('foo.bar', make_exists(1))
assert 'foo.bar-10' == get_unique_filename('foo.bar', make_exists(10))
assert 'foo.bar' == get_unique_filename('foo.bar', attempts(0))
assert 'foo.bar-1' == get_unique_filename('foo.bar', attempts(1))
assert 'foo.bar-10' == get_unique_filename('foo.bar', attempts(10))
class DownloadsTest(TestCase):
@ -95,14 +103,8 @@ class DownloadsTest(TestCase):
def test_actual_download(self):
url = httpbin('/robots.txt')
body = urlopen(url).read().decode()
r = http(
'--download',
url,
env=TestEnvironment(
stdin_isatty=True,
stdout_isatty=False
)
)
env = TestEnvironment(stdin_isatty=True, stdout_isatty=False)
r = http('--download', url, env=env)
assert 'Downloading' in r.stderr
assert '[K' in r.stderr
assert 'Done' in r.stderr
@ -112,7 +114,7 @@ class DownloadsTest(TestCase):
download = Download(output_file=open(os.devnull, 'w'))
download.start(Response(
url=httpbin('/'),
headers={'Content-Length': 10}
headers={'Content-Length': 10}
))
time.sleep(1.1)
download.chunk_downloaded(b'12345')

View File

@ -8,42 +8,30 @@ from tests import TestEnvironment, http, httpbin, HTTP_OK
class ExitStatusTest(TestCase):
def test_ok_response_exits_0(self):
r = http(
'GET',
httpbin('/status/200')
)
r = http('GET', httpbin('/status/200'))
assert HTTP_OK in r
assert r.exit_status == ExitStatus.OK
def test_error_response_exits_0_without_check_status(self):
r = http(
'GET',
httpbin('/status/500')
)
r = http('GET', httpbin('/status/500'))
assert 'HTTP/1.1 500' in r
assert r.exit_status == ExitStatus.OK
assert not r.stderr
@pytest.mark.skipif(True, reason='timeout broken in requests'
' (https://github.com/jkbr/httpie/issues/185)')
@pytest.mark.skipif(
True,
reason='timeout broken in requests'
' (https://github.com/jkbr/httpie/issues/185)')
def test_timeout_exit_status(self):
r = http(
'--timeout=0.5',
'GET',
httpbin('/delay/1')
)
r = http('--timeout=0.5', 'GET', httpbin('/delay/1'))
assert HTTP_OK in r
assert r.exit_status == ExitStatus.ERROR_TIMEOUT
def test_3xx_check_status_exits_3_and_stderr_when_stdout_redirected(self):
r = http(
'--check-status',
'--headers', # non-terminal, force headers
'GET',
httpbin('/status/301'),
env=TestEnvironment(stdout_isatty=False,)
)
env = TestEnvironment(stdout_isatty=False)
r = http('--check-status', '--headers', 'GET', httpbin('/status/301'),
env=env)
assert 'HTTP/1.1 301' in r
assert r.exit_status == ExitStatus.ERROR_HTTP_3XX
assert '301 moved permanently' in r.stderr.lower()
@ -52,32 +40,19 @@ class ExitStatusTest(TestCase):
requests.__version__ == '0.13.6',
reason='Redirects with prefetch=False are broken in Requests 0.13.6')
def test_3xx_check_status_redirects_allowed_exits_0(self):
r = http(
'--check-status',
'--follow',
'GET',
httpbin('/status/301')
)
r = http('--check-status', '--follow', 'GET', httpbin('/status/301'))
# The redirect will be followed so 200 is expected.
assert 'HTTP/1.1 200 OK' in r
assert r.exit_status == ExitStatus.OK
def test_4xx_check_status_exits_4(self):
r = http(
'--check-status',
'GET',
httpbin('/status/401')
)
r = http('--check-status', 'GET', httpbin('/status/401'))
assert 'HTTP/1.1 401' in r
assert r.exit_status == ExitStatus.ERROR_HTTP_4XX
# Also stderr should be empty since stdout isn't redirected.
assert not r.stderr
def test_5xx_check_status_exits_5(self):
r = http(
'--check-status',
'GET',
httpbin('/status/500')
)
r = http('--check-status', 'GET', httpbin('/status/500'))
assert 'HTTP/1.1 500' in r
assert r.exit_status == ExitStatus.ERROR_HTTP_5XX

View File

@ -8,81 +8,43 @@ from tests.fixtures import FILE_PATH, FILE_CONTENT
class HTTPieTest(TestCase):
def test_GET(self):
r = http(
'GET',
httpbin('/get')
)
r = http('GET', httpbin('/get'))
assert HTTP_OK in r
def test_DELETE(self):
r = http(
'DELETE',
httpbin('/delete')
)
r = http('DELETE', httpbin('/delete'))
assert HTTP_OK in r
def test_PUT(self):
r = http(
'PUT',
httpbin('/put'),
'foo=bar'
)
r = http('PUT', httpbin('/put'), 'foo=bar')
assert HTTP_OK in r
assert r'\"foo\": \"bar\"' in r
def test_POST_JSON_data(self):
r = http(
'POST',
httpbin('/post'),
'foo=bar'
)
r = http('POST', httpbin('/post'), 'foo=bar')
assert HTTP_OK in r
assert r'\"foo\": \"bar\"' in r
def test_POST_form(self):
r = http(
'--form',
'POST',
httpbin('/post'),
'foo=bar'
)
r = http('--form', 'POST', httpbin('/post'), 'foo=bar')
assert HTTP_OK in r
assert '"foo": "bar"' in r
def test_POST_form_multiple_values(self):
r = http(
'--form',
'POST',
httpbin('/post'),
'foo=bar',
'foo=baz',
)
r = http('--form', 'POST', httpbin('/post'), 'foo=bar', 'foo=baz')
assert HTTP_OK in r
assert r.json['form'] == {'foo': ['bar', 'baz']}
def test_POST_stdin(self):
with open(FILE_PATH) as f:
env = TestEnvironment(
stdin=f,
stdin_isatty=False,
)
r = http(
'--form',
'POST',
httpbin('/post'),
env=env
)
env = TestEnvironment(stdin=f, stdin_isatty=False)
r = http('--form', 'POST', httpbin('/post'), env=env)
assert HTTP_OK in r
assert FILE_CONTENT in r
def test_headers(self):
r = http(
'GET',
httpbin('/headers'),
'Foo:bar'
)
r = http('GET', httpbin('/headers'), 'Foo:bar')
assert HTTP_OK in r
assert '"User-Agent": "HTTPie' in r
assert '"Foo": "bar"' in r

View File

@ -9,38 +9,20 @@ from tests import (
class VerboseFlagTest(TestCase):
def test_verbose(self):
r = http(
'--verbose',
'GET',
httpbin('/get'),
'test-header:__test__'
)
r = http('--verbose', 'GET', httpbin('/get'), 'test-header:__test__')
assert HTTP_OK in r
assert r.count('__test__') == 2
def test_verbose_form(self):
# https://github.com/jkbr/httpie/issues/53
r = http(
'--verbose',
'--form',
'POST',
httpbin('/post'),
'foo=bar',
'baz=bar'
)
r = http('--verbose', '--form', 'POST', httpbin('/post'),
'foo=bar', 'baz=bar')
assert HTTP_OK in r
assert 'foo=bar&baz=bar' in r
def test_verbose_json(self):
r = http(
'--verbose',
'POST',
httpbin('/post'),
'foo=bar',
'baz=bar'
)
r = http('--verbose', 'POST', httpbin('/post'), 'foo=bar', 'baz=bar')
assert HTTP_OK in r
assert '"baz": "bar"' in r # request
assert r'\"baz\": \"bar\"' in r # response
@ -50,35 +32,21 @@ class PrettyOptionsTest(TestCase):
"""Test the --pretty flag handling."""
def test_pretty_enabled_by_default(self):
r = http(
'GET',
httpbin('/get'),
env=TestEnvironment(colors=256),
)
env = TestEnvironment(colors=256)
r = http('GET', httpbin('/get'), env=env)
assert COLOR in r
def test_pretty_enabled_by_default_unless_stdout_redirected(self):
r = http(
'GET',
httpbin('/get')
)
r = http('GET', httpbin('/get'))
assert COLOR not in r
def test_force_pretty(self):
r = http(
'--pretty=all',
'GET',
httpbin('/get'),
env=TestEnvironment(stdout_isatty=False, colors=256),
)
env = TestEnvironment(stdout_isatty=False, colors=256)
r = http('--pretty=all', 'GET', httpbin('/get'), env=env, )
assert COLOR in r
def test_force_ugly(self):
r = http(
'--pretty=none',
'GET',
httpbin('/get'),
)
r = http('--pretty=none', 'GET', httpbin('/get'))
assert COLOR not in r
def test_subtype_based_pygments_lexer_match(self):
@ -86,49 +54,34 @@ class PrettyOptionsTest(TestCase):
match any lexer.
"""
r = http(
'--print=B',
'--pretty=all',
httpbin('/post'),
'Content-Type:text/foo+json',
'a=b',
env=TestEnvironment(colors=256)
)
env = TestEnvironment(colors=256)
r = http('--print=B', '--pretty=all', httpbin('/post'),
'Content-Type:text/foo+json', 'a=b', env=env)
assert COLOR in r
def test_colors_option(self):
r = http(
'--print=B',
'--pretty=colors',
'GET',
httpbin('/get'),
'a=b',
env=TestEnvironment(colors=256),
)
#noinspection PyUnresolvedReferences
env = TestEnvironment(colors=256)
r = http('--print=B', '--pretty=colors', 'GET', httpbin('/get'), 'a=b',
env=env)
# Tests that the JSON data isn't formatted.
assert not r.strip().count('\n')
assert COLOR in r
def test_format_option(self):
r = http(
'--print=B',
'--pretty=format',
'GET',
httpbin('/get'),
'a=b',
env=TestEnvironment(colors=256),
)
#noinspection PyUnresolvedReferences
env = TestEnvironment(colors=256)
r = http('--print=B', '--pretty=format', 'GET', httpbin('/get'), 'a=b',
env=env)
# Tests that the JSON data is formatted.
assert r.strip().count('\n') == 2
assert COLOR not in r
class LineEndingsTest(TestCase):
"""Test that CRLF is properly used in headers and
as the headers/body separator."""
"""
Test that CRLF is properly used in headers
and as the headers/body separator.
"""
def _validate_crlf(self, msg):
lines = iter(msg.splitlines(True))
for header in lines:
@ -142,45 +95,23 @@ class LineEndingsTest(TestCase):
return body
def test_CRLF_headers_only(self):
r = http(
'--headers',
'GET',
httpbin('/get')
)
r = http('--headers', 'GET', httpbin('/get'))
body = self._validate_crlf(r)
assert not body, 'Garbage after headers: %r' % r
def test_CRLF_ugly_response(self):
r = http(
'--pretty=none',
'GET',
httpbin('/get')
)
r = http('--pretty=none', 'GET', httpbin('/get'))
self._validate_crlf(r)
def test_CRLF_formatted_response(self):
r = http(
'--pretty=format',
'GET',
httpbin('/get')
)
r = http('--pretty=format', 'GET', httpbin('/get'))
assert r.exit_status == ExitStatus.OK
self._validate_crlf(r)
def test_CRLF_ugly_request(self):
r = http(
'--pretty=none',
'--print=HB',
'GET',
httpbin('/get')
)
r = http('--pretty=none', '--print=HB', 'GET', httpbin('/get'))
self._validate_crlf(r)
def test_CRLF_formatted_request(self):
r = http(
'--pretty=format',
'--print=HB',
'GET',
httpbin('/get')
)
r = http('--pretty=format', '--print=HB', 'GET', httpbin('/get'))
self._validate_crlf(r)

View File

@ -6,7 +6,6 @@ from tests import TestEnvironment, mk_config_dir, http, httpbin, HTTP_OK
class SessionsTest(TestCase):
@property
def env(self):
return TestEnvironment(config_dir=self.config_dir)
@ -15,15 +14,9 @@ class SessionsTest(TestCase):
# Start a full-blown session with a custom request header,
# authorization, and response cookies.
self.config_dir = mk_config_dir()
r = http(
'--follow',
'--session=test',
'--auth=username:password',
'GET',
httpbin('/cookies/set?hello=world'),
'Hello:World',
env=self.env
)
r = http('--follow', '--session=test', '--auth=username:password',
'GET', httpbin('/cookies/set?hello=world'), 'Hello:World',
env=self.env)
assert HTTP_OK in r
def tearDown(self):
@ -31,66 +24,37 @@ class SessionsTest(TestCase):
def test_session_create(self):
# Verify that the session has been created.
r = http(
'--session=test',
'GET',
httpbin('/get'),
env=self.env
)
r = http('--session=test', 'GET', httpbin('/get'), env=self.env)
assert HTTP_OK in r
assert r.json['headers']['Hello'] == 'World'
assert r.json['headers']['Cookie'] == 'hello=world'
assert 'Basic ' in r.json['headers']['Authorization']
def test_session_ignored_header_prefixes(self):
r = http(
'--session=test',
'GET',
httpbin('/get'),
'Content-Type: text/plain',
'If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT',
env=self.env
)
r = http('--session=test', 'GET', httpbin('/get'),
'Content-Type: text/plain',
'If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT',
env=self.env)
assert HTTP_OK in r
r2 = http(
'--session=test',
'GET',
httpbin('/get')
)
r2 = http('--session=test', 'GET', httpbin('/get'))
assert HTTP_OK in r2
assert 'Content-Type' not in r2.json['headers']
assert 'If-Unmodified-Since' not in r2.json['headers']
def test_session_update(self):
# Get a response to a request from the original session.
r1 = http(
'--session=test',
'GET',
httpbin('/get'),
env=self.env
)
r1 = http('--session=test', 'GET', httpbin('/get'), env=self.env)
assert HTTP_OK in r1
# Make a request modifying the session data.
r2 = http(
'--follow',
'--session=test',
'--auth=username:password2',
'GET',
httpbin('/cookies/set?hello=world2'),
'Hello:World2',
env=self.env
)
r2 = http('--follow', '--session=test', '--auth=username:password2',
'GET', httpbin('/cookies/set?hello=world2'), 'Hello:World2',
env=self.env)
assert HTTP_OK in r2
# Get a response to a request from the updated session.
r3 = http(
'--session=test',
'GET',
httpbin('/get'),
env=self.env
)
r3 = http('--session=test', 'GET', httpbin('/get'), env=self.env)
assert HTTP_OK in r3
assert r3.json['headers']['Hello'] == 'World2'
assert r3.json['headers']['Cookie'] == 'hello=world2'
@ -99,34 +63,19 @@ class SessionsTest(TestCase):
def test_session_read_only(self):
# Get a response from the original session.
r1 = http(
'--session=test',
'GET',
httpbin('/get'),
env=self.env
)
r1 = http('--session=test', 'GET', httpbin('/get'), env=self.env)
assert HTTP_OK in r1
# Make a request modifying the session data but
# with --session-read-only.
r2 = http(
'--follow',
'--session-read-only=test',
'--auth=username:password2',
'GET',
httpbin('/cookies/set?hello=world2'),
'Hello:World2',
env=self.env
)
r2 = http('--follow', '--session-read-only=test',
'--auth=username:password2', 'GET',
httpbin('/cookies/set?hello=world2'), 'Hello:World2',
env=self.env)
assert HTTP_OK in r2
# Get a response from the updated session.
r3 = http(
'--session=test',
'GET',
httpbin('/get'),
env=self.env
)
r3 = http('--session=test', 'GET', httpbin('/get'), env=self.env)
assert HTTP_OK in r3
# Origin can differ on Travis.
@ -139,21 +88,11 @@ class SessionsTest(TestCase):
def test_session_by_path(self):
session_path = os.path.join(self.config_dir, 'session-by-path.json')
r1 = http(
'--session=' + session_path,
'GET',
httpbin('/get'),
'Foo:Bar',
env=self.env
)
r1 = http('--session=' + session_path, 'GET', httpbin('/get'),
'Foo:Bar', env=self.env)
assert HTTP_OK in r1
r2 = http(
'--session=' + session_path,
'GET',
httpbin('/get'),
env=self.env
)
r2 = http('--session=' + session_path, 'GET', httpbin('/get'),
env=self.env)
assert HTTP_OK in r2
assert r2.json['headers']['Foo'] in 'Bar'

View File

@ -16,19 +16,11 @@ class StreamTest(TestCase):
def test_pretty_redirected_stream(self):
"""Test that --stream works with prettified redirected output."""
with open(BIN_FILE_PATH, 'rb') as f:
r = http(
'--verbose',
'--pretty=all',
'--stream',
'GET',
httpbin('/get'),
env=TestEnvironment(
colors=256,
stdin=f,
stdin_isatty=False,
stdout_isatty=False,
)
)
env = TestEnvironment(colors=256, stdin=f,
stdin_isatty=False,
stdout_isatty=False)
r = http('--verbose', '--pretty=all', '--stream', 'GET',
httpbin('/get'), env=env)
assert BINARY_SUPPRESSED_NOTICE.decode() in r
# We get 'Bad Request' but it's okay.
#self.assertIn(OK_COLOR, r)
@ -37,17 +29,9 @@ class StreamTest(TestCase):
"""Test that --stream works with non-prettified
redirected terminal output."""
with open(BIN_FILE_PATH, 'rb') as f:
r = http(
'--pretty=none',
'--stream',
'--verbose',
'GET',
httpbin('/get'),
env=TestEnvironment(
stdin=f,
stdin_isatty=False
),
)
env = TestEnvironment(stdin=f, stdin_isatty=False)
r = http('--pretty=none', '--stream', '--verbose', 'GET',
httpbin('/get'), env=env)
assert BINARY_SUPPRESSED_NOTICE.decode() in r
# We get 'Bad Request' but it's okay.
#self.assertIn(OK, r)
@ -56,18 +40,10 @@ class StreamTest(TestCase):
"""Test that --stream works with non-prettified
redirected terminal output."""
with open(BIN_FILE_PATH, 'rb') as f:
r = http(
'--pretty=none',
'--stream',
'--verbose',
'GET',
httpbin('/get'),
env=TestEnvironment(
stdout_isatty=False,
stdin=f,
stdin_isatty=False
)
)
env = TestEnvironment(stdout_isatty=False, stdin=f,
stdin_isatty=False)
r = http('--pretty=none', '--stream', '--verbose', 'GET',
httpbin('/get'), env=env)
# We get 'Bad Request' but it's okay.
#self.assertIn(OK.encode(), r)
assert BIN_FILE_CONTENT in r

View File

@ -7,25 +7,13 @@ from tests.fixtures import FILE_PATH_ARG, FILE_PATH, FILE_CONTENT
class MultipartFormDataFileUploadTest(TestCase):
def test_non_existent_file_raises_parse_error(self):
self.assertRaises(ParseError, http,
'--form',
'POST',
httpbin('/post'),
'foo@/__does_not_exist__',
)
with self.assertRaises(ParseError):
http('--form', 'POST', httpbin('/post'), 'foo@/__does_not_exist__')
def test_upload_ok(self):
r = http(
'--form',
'--verbose',
'POST',
httpbin('/post'),
'test-file@%s' % FILE_PATH_ARG,
'foo=bar'
)
r = http('--form', '--verbose', 'POST', httpbin('/post'),
'test-file@%s' % FILE_PATH_ARG, 'foo=bar')
assert HTTP_OK in r
assert 'Content-Disposition: form-data; name="foo"' in r
assert 'Content-Disposition: form-data; name="test-file";' \
@ -39,44 +27,28 @@ class RequestBodyFromFilePathTest(TestCase):
`http URL @file'
"""
def test_request_body_from_file_by_path(self):
r = http(
'--verbose',
'POST',
httpbin('/post'),
'@' + FILE_PATH_ARG
)
r = http('--verbose', 'POST', httpbin('/post'), '@' + FILE_PATH_ARG)
assert HTTP_OK in r
assert FILE_CONTENT in r
assert '"Content-Type": "text/plain"' in r
def test_request_body_from_file_by_path_with_explicit_content_type(self):
r = http(
'POST',
httpbin('/post'),
'@' + FILE_PATH_ARG,
'Content-Type:x-foo/bar'
)
r = http('POST', httpbin('/post'), '@' + FILE_PATH_ARG,
'Content-Type:x-foo/bar')
assert HTTP_OK in r
assert FILE_CONTENT in r
assert '"Content-Type": "x-foo/bar"' in r
def test_request_body_from_file_by_path_no_field_name_allowed(self):
env = TestEnvironment(stdin_isatty=True)
r = http(
'POST',
httpbin('/post'),
'field-name@' + FILE_PATH_ARG,
env=env
)
r = http('POST', httpbin('/post'), 'field-name@' + FILE_PATH_ARG,
env=env)
assert 'perhaps you meant --form?' in r.stderr
def test_request_body_from_file_by_path_no_data_items_allowed(self):
r = http(
'POST',
httpbin('/post'),
'@' + FILE_PATH_ARG,
'foo=bar',
env=TestEnvironment(stdin_isatty=False)
)
env = TestEnvironment(stdin_isatty=False)
r = http('POST', httpbin('/post'), '@' + FILE_PATH_ARG, 'foo=bar',
env=env)
assert 'cannot be mixed' in r.stderr

View File

@ -9,7 +9,6 @@ from httpie.compat import is_windows
class WindowsOnlyTests(TestCase):
@pytest.mark.skipif(not is_windows, reason='windows-only')
def test_windows_colorized_output(self):
# Spits out the colorized output.
@ -17,15 +16,9 @@ class WindowsOnlyTests(TestCase):
class FakeWindowsTest(TestCase):
def test_output_file_pretty_not_allowed_on_windows(self):
r = http(
'--output',
os.path.join(tempfile.gettempdir(), '__httpie_test_output__'),
'--pretty=all',
'GET',
httpbin('/get'),
env=TestEnvironment(is_windows=True)
)
env = TestEnvironment(is_windows=True)
r = http('--output',
os.path.join(tempfile.gettempdir(), '__httpie_test_output__'),
'--pretty=all', 'GET', httpbin('/get'), env=env)
assert 'Only terminal output can be colorized on Windows' in r.stderr