1
0
mirror of https://github.com/httpie/cli.git synced 2025-10-30 23:47:52 +02:00

Tests, docs, clean-up.

Closes #54.
This commit is contained in:
Jakub Roztocil
2012-06-24 03:43:08 +02:00
parent 4613d947a8
commit 926d3f5caf
7 changed files with 260 additions and 233 deletions

View File

@@ -5,8 +5,6 @@ python:
- pypy - pypy
- 3.1 - 3.1
- 3.2 - 3.2
script: python tests/tests.py script: python setup.py test
install: install:
- pip install requests pygments - pip install . --use-mirrors
- "if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]] || [[ $TRAVIS_PYTHON_VERSION == '3.1' ]]; then pip install argparse; fi"

View File

@@ -104,28 +104,28 @@ Flags
Most of the flags mirror the arguments understood by ``requests.request``. See ``http -h`` for more details:: Most of the flags mirror the arguments understood by ``requests.request``. See ``http -h`` for more details::
usage: http [-h] [--version] [--json | --form] [--traceback] usage: http [-h] [--version] [--json | --form] [--traceback]
[--pretty | --ugly] [--pretty | --ugly]
[--print OUTPUT_OPTIONS | --verbose | --headers | --body] [--print OUTPUT_OPTIONS | --verbose | --headers | --body]
[--style STYLE] [--auth AUTH] [--auth-type {basic,digest}] [--style STYLE] [--auth AUTH] [--auth-type {basic,digest}]
[--verify VERIFY] [--proxy PROXY] [--allow-redirects] [--verify VERIFY] [--proxy PROXY] [--allow-redirects]
[--timeout TIMEOUT] [--timeout TIMEOUT]
[METHOD] URL [ITEM [ITEM ...]] [METHOD] URL [ITEM [ITEM ...]]
HTTPie - cURL for humans. <http://httpie.org> HTTPie - cURL for humans. <http://httpie.org>
positional arguments: positional arguments:
METHOD The HTTP method to be used for the request (GET, POST, METHOD The HTTP method to be used for the request (GET, POST,
PUT, DELETE, PATCH, ...). If this argument is omitted PUT, DELETE, PATCH, ...). If this argument is omitted,
then httpie will guess HTTP method. If there is either then HTTPie will guess the HTTP method. If there is
simple data field or JSON data field or file field some data to be sent, then it will be POST, otherwise
presents then method is POST otherwise it is GET. GET.
URL The protocol defaults to http:// if the URL does not URL The protocol defaults to http:// if the URL does not
include one. include one.
ITEM A key-value pair whose type is defined by the ITEM A key-value pair whose type is defined by the
separator used. It can be an HTTP header separator used. It can be an HTTP header
(header:value), a data field to be used in the request (header:value), a data field to be used in the request
body (field_name=value), a raw JSON data field body (field_name=value), a raw JSON data field
(field_name:=value) or a file field (field_name:=value), or a file field
(field_name@/path/to/file). You can use a backslash to (field_name@/path/to/file). You can use a backslash to
escape a colliding separator in the field name. escape a colliding separator in the field name.
@@ -159,12 +159,12 @@ Most of the flags mirror the arguments understood by ``requests.request``. See `
--style STYLE, -s STYLE --style STYLE, -s STYLE
Output coloring style, one of autumn, borland, bw, Output coloring style, one of autumn, borland, bw,
colorful, default, emacs, friendly, fruity, manni, colorful, default, emacs, friendly, fruity, manni,
monokai, murphy, native, pastie, perldoc, solarized, monokai, murphy, native, pastie, perldoc, rrt,
tango, trac, vim, vs. Defaults to solarized. For this solarized, tango, trac, vim, vs. Defaults to
option to work properly, please make sure that the solarized. For this option to work properly, please
$TERM environment variable is set to "xterm-256color" make sure that the $TERM environment variable is set
or similar (e.g., via `export TERM=xterm-256color' in to "xterm-256color" or similar (e.g., via `export TERM
your ~/.bashrc). =xterm-256color' in your ~/.bashrc).
--auth AUTH, -a AUTH username:password --auth AUTH, -a AUTH username:password
--auth-type {basic,digest} --auth-type {basic,digest}
The authentication mechanism to be used. Defaults to The authentication mechanism to be used. Defaults to
@@ -189,7 +189,7 @@ Contribute
If you have found a bug or have a feature request, the `issue tracker <https://github.com/jkbr/httpie/issues?state=open>`_ is the place to start a discussion about it. If you have found a bug or have a feature request, the `issue tracker <https://github.com/jkbr/httpie/issues?state=open>`_ is the place to start a discussion about it.
To contribute code or documentation, please first browse the exsiting issues to see if the feature/bug has previously been discussed. Then fork `the repository <https://github.com/jkbr/httpie>`_, make changes in your develop branch and submit a pull request. Note: Pull requests with tests and documentation are 53.6% more awesome :) To contribute code or documentation, please first browse the existing issues to see if the feature/bug has previously been discussed. Then fork `the repository <https://github.com/jkbr/httpie>`_, make changes in your develop branch and submit a pull request. Note: Pull requests with tests and documentation are 53.6% more awesome :)
Before a pull requests is submitted, it's a good idea to run the existing suite of tests:: Before a pull requests is submitted, it's a good idea to run the existing suite of tests::
@@ -206,7 +206,9 @@ Before a pull requests is submitted, it's a good idea to run the existing suite
Changelog Changelog
--------- ---------
* `New in development version <https://github.com/jkbr/httpie/compare/0.2.1...master>`_ * `0.2.2dev <https://github.com/jkbr/httpie/compare/0.2.1...master>`_
* The ``METHOD`` positional argument can now be omitted (defaults to ``GET``, or to ``POST`` with data).
* Fixed --verbose --form.
* `0.2.1 <https://github.com/jkbr/httpie/compare/0.2.0...0.2.1>`_ (2012-06-13) * `0.2.1 <https://github.com/jkbr/httpie/compare/0.2.0...0.2.1>`_ (2012-06-13)
* Added compatibility with ``requests-0.12.1``. * Added compatibility with ``requests-0.12.1``.
* Dropped custom JSON and HTTP lexers in favor of the ones newly included in ``pygments-1.5``. * Dropped custom JSON and HTTP lexers in favor of the ones newly included in ``pygments-1.5``.

View File

@@ -14,7 +14,7 @@ def _(text):
desc = '%s <http://httpie.org>' desc = '%s <http://httpie.org>'
parser = cliparse.HTTPieArgumentParser(description=desc % __doc__.strip(),) parser = cliparse.Parser(description=desc % __doc__.strip(),)
parser.add_argument('--version', action='version', version=__version__) parser.add_argument('--version', action='version', version=__version__)
@@ -176,8 +176,8 @@ parser.add_argument(
help=_(''' help=_('''
The HTTP method to be used for the request The HTTP method to be used for the request
(GET, POST, PUT, DELETE, PATCH, ...). (GET, POST, PUT, DELETE, PATCH, ...).
If this argument is omitted then httpie will guess the HTTP method. If this argument is omitted, then HTTPie will guess the HTTP method.
If there is any data to be sent then method is POST otherwise it is GET. If there is some data to be sent, then it will be POST, otherwise GET.
''') ''')
) )
parser.add_argument( parser.add_argument(
@@ -200,7 +200,7 @@ parser.add_argument(
A key-value pair whose type is defined by the separator used. It can be an A key-value pair whose type is defined by the separator used. It can be an
HTTP header (header:value), HTTP header (header:value),
a data field to be used in the request body (field_name=value), a data field to be used in the request body (field_name=value),
a raw JSON data field (field_name:=value) a raw JSON data field (field_name:=value),
or a file field (field_name@/path/to/file). or a file field (field_name@/path/to/file).
You can use a backslash to escape a colliding separator in the field name. You can use a backslash to escape a colliding separator in the field name.
''') ''')

View File

@@ -25,11 +25,11 @@ SEP_HEADERS = SEP_COMMON
SEP_DATA = '=' SEP_DATA = '='
SEP_DATA_RAW_JSON = ':=' SEP_DATA_RAW_JSON = ':='
SEP_FILES = '@' SEP_FILES = '@'
DATA_ITEM_SEPARATORS = { DATA_ITEM_SEPARATORS = [
SEP_DATA, SEP_DATA,
SEP_DATA_RAW_JSON, SEP_DATA_RAW_JSON,
SEP_FILES SEP_FILES
} ]
OUT_REQ_HEADERS = 'H' OUT_REQ_HEADERS = 'H'
@@ -47,12 +47,12 @@ PRETTIFY_STDOUT_TTY_ONLY = object()
DEFAULT_UA = 'HTTPie/%s' % __version__ DEFAULT_UA = 'HTTPie/%s' % __version__
class HTTPieArgumentParser(argparse.ArgumentParser): class Parser(argparse.ArgumentParser):
def parse_args(self, args=None, namespace=None, def parse_args(self, args=None, namespace=None,
stdin=sys.stdin, stdin=sys.stdin,
stdin_isatty=sys.stdin.isatty()): stdin_isatty=sys.stdin.isatty()):
args = super(HTTPieArgumentParser, self).parse_args(args, namespace) args = super(Parser, self).parse_args(args, namespace)
self._validate_output_options(args) self._validate_output_options(args)
self._validate_auth_options(args) self._validate_auth_options(args)
self._guess_method(args, stdin_isatty) self._guess_method(args, stdin_isatty)
@@ -68,28 +68,9 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
args.data = stdin.read() args.data = stdin.read()
def _guess_method(self, args, stdin_isatty=sys.stdin.isatty()): def _guess_method(self, args, stdin_isatty=sys.stdin.isatty()):
"""Suggests HTTP method by positional argument values. """
Set `args.method`, if not specified, to either POST or GET
In following description by data item it means one of: based on whether the request has data or not.
* simple data item (key=value)
* JSON raw item (key:=value)
* file item (key@value)
If METHOD argument is omitted and no data ITEM is given then method is GET:
http http://example.com/
- is shortcut for -
http GET http://example.com.
If METHOD argument is omitted but at least one data ITEM
is present then method is POST:
http http://example.com/ hello=world
- is shortcut for -
http POST http://example.com hello=world.
If METHOD is specified then http behaves as it is now.
The first argument should be treated as method
if it matches ^[a-zA-Z]+$ regexp. Otherwise it is url.
""" """
if args.method is None: if args.method is None:

View File

@@ -5,12 +5,14 @@ import httpie
if sys.argv[-1] == 'test': if sys.argv[-1] == 'test':
os.system('python tests/tests.py') sys.exit(os.system('python tests/tests.py'))
sys.exit()
# Debian has only requests==0.10.1 and httpie.deb depends on that. requirements = [
requirements = ['requests>=0.10.1', 'Pygments>=1.5'] # Debian has only requests==0.10.1 and httpie.deb depends on that.
'requests>=0.10.1',
'Pygments>=1.5'
]
if sys.version_info[:2] in ((2, 6), (3, 1)): if sys.version_info[:2] in ((2, 6), (3, 1)):
# argparse has been added in Python 3.2 / 2.7 # argparse has been added in Python 3.2 / 2.7
requirements.append('argparse>=1.2.1') requirements.append('argparse>=1.2.1')

View File

@@ -1,75 +0,0 @@
import unittest
from argparse import Namespace
from httpie.cliparse import HTTPieArgumentParser, KeyValue
__author__ = 'vladimir'
class HTTPieArgumentParserTestCase(unittest.TestCase):
def setUp(self):
self.HTTPieArgumentParserStub = type(HTTPieArgumentParser.__name__, (HTTPieArgumentParser,), {})
self.HTTPieArgumentParserStub.__init__ = lambda self: None
self.parser = HTTPieArgumentParser()
def test_guess_when_method_set_and_valid(self):
args = Namespace()
args.method = 'GET'
args.url = 'http://example.com/'
args.items = []
self.parser._guess_method(args)
self.assertEquals(args.method, 'GET')
self.assertEquals(args.url, 'http://example.com/')
self.assertEquals(args.items, [])
def test_guess_when_method_not_set(self):
args = Namespace()
args.method = None
args.url = 'http://example.com/'
args.items = []
self.parser._guess_method(args)
self.assertEquals(args.method, 'GET')
self.assertEquals(args.url, 'http://example.com/')
self.assertEquals(args.items, [])
def test_guess_when_method_set_but_invalid_and_data_field(self):
args = Namespace()
args.method = 'http://example.com/'
args.url = 'data=field'
args.items = []
self.parser._guess_method(args)
self.assertEquals(args.method, 'POST')
self.assertEquals(args.url, 'http://example.com/')
self.assertEquals(args.items, [KeyValue(key='data', value='field', sep='=', orig='data=field')])
def test_guess_when_method_set_but_invalid_and_header_field(self):
args = Namespace()
args.method = 'http://example.com/'
args.url = 'test:header'
args.items = []
self.parser._guess_method(args)
self.assertEquals(args.method, 'GET')
self.assertEquals(args.url, 'http://example.com/')
self.assertEquals(args.items, [KeyValue(key='test', value='header', sep=':', orig='test:header')])
def test_guess_when_method_set_but_invalid_and_item_exists(self):
args = Namespace()
args.method = 'http://example.com/'
args.url = 'new_item=a'
args.items = [KeyValue(key='old_item', value='b', sep='=', orig='old_item=b')]
self.parser._guess_method(args)
self.assertEquals(args.items, [
KeyValue(key='new_item', value='a', sep='=', orig='new_item=a'),
KeyValue(key='old_item', value='b', sep='=', orig='old_item=b'),
])

View File

@@ -1,24 +1,36 @@
# coding:utf-8 """
import os High-level tests.
import sys
"""
import unittest import unittest
import argparse import argparse
from requests.compat import is_py26 import os
import sys
import tempfile import tempfile
from requests.compat import is_py26
#################################################################
# Utils/setup
#################################################################
# HACK: Prepend ../ to PYTHONPATH so that we can import httpie form there.
TESTS_ROOT = os.path.dirname(__file__) TESTS_ROOT = os.path.dirname(__file__)
sys.path.insert(0, os.path.realpath(os.path.join(TESTS_ROOT, '..'))) sys.path.insert(0, os.path.realpath(os.path.join(TESTS_ROOT, '..')))
from httpie import __main__ from httpie import __main__, cliparse
from httpie import cliparse
TEST_FILE = os.path.join(TESTS_ROOT, 'file.txt') TEST_FILE_PATH = os.path.join(TESTS_ROOT, 'file.txt')
TERMINAL_COLOR_PRESENCE_CHECK = '\x1b[' TERMINAL_COLOR_PRESENCE_CHECK = '\x1b['
def http(*args, **kwargs): def http(*args, **kwargs):
"""
Invoke `httpie.__main__.main` with `args` and `kwargs`,
and return a unicode response.
"""
http_kwargs = { http_kwargs = {
'stdin_isatty': True, 'stdin_isatty': True,
'stdout_isatty': False 'stdout_isatty': False
@@ -32,7 +44,7 @@ def http(*args, **kwargs):
return response return response
class BaseTest(unittest.TestCase): class BaseTestCase(unittest.TestCase):
if is_py26: if is_py26:
def assertIn(self, member, container, msg=None): def assertIn(self, member, container, msg=None):
@@ -46,7 +58,149 @@ class BaseTest(unittest.TestCase):
self.assertEqual(sorted(d1.values()), sorted(d2.values()), msg) self.assertEqual(sorted(d1.values()), sorted(d2.values()), msg)
class TestItemParsing(BaseTest): #################################################################
# High-level tests using httpbin.org.
#################################################################
class HTTPieTest(BaseTestCase):
def test_GET(self):
r = http('GET', 'http://httpbin.org/get')
self.assertIn('HTTP/1.1 200', r)
def test_DELETE(self):
r = http('DELETE', 'http://httpbin.org/delete')
self.assertIn('HTTP/1.1 200', r)
def test_PUT(self):
r = http('PUT', 'http://httpbin.org/put', 'foo=bar')
self.assertIn('HTTP/1.1 200', r)
self.assertIn('"foo": "bar"', r)
def test_POST_JSON_data(self):
r = http('POST', 'http://httpbin.org/post', 'foo=bar')
self.assertIn('HTTP/1.1 200', r)
self.assertIn('"foo": "bar"', r)
def test_GET_JSON_implicit_accept(self):
r = http('-j', 'GET', 'http://httpbin.org/headers')
self.assertIn('HTTP/1.1 200', r)
self.assertIn('"Accept": "application/json"', r)
def test_GET_JSON_explicit_accept(self):
r = http('-j', 'GET', 'http://httpbin.org/headers', 'Accept:application/xml')
self.assertIn('HTTP/1.1 200', r)
self.assertIn('"Accept": "application/xml"', r)
def test_POST_form(self):
response = http('--form', 'POST', 'http://httpbin.org/post', 'foo=bar')
self.assertIn('"foo": "bar"', response)
def test_POST_stdin(self):
r = http('--form', 'POST', 'http://httpbin.org/post',
stdin=open(TEST_FILE_PATH), stdin_isatty=False)
self.assertIn('HTTP/1.1 200', r)
def test_headers(self):
response = http('GET', 'http://httpbin.org/headers', 'Foo:bar')
self.assertIn('"User-Agent": "HTTPie', response)
self.assertIn('"Foo": "bar"', response)
class ImplicitHTTPMethodTest(BaseTestCase):
def test_implicit_GET(self):
r = http('http://httpbin.org/get')
self.assertIn('HTTP/1.1 200', r)
def test_implicit_GET_with_headers(self):
r = http('http://httpbin.org/headers', 'Foo:bar')
self.assertIn('"Foo": "bar"', r)
self.assertIn('HTTP/1.1 200', r)
def test_implicit_POST_json(self):
r = http('http://httpbin.org/post', 'hello=world')
self.assertIn('"hello": "world"', r)
self.assertIn('HTTP/1.1 200', r)
def test_implicit_POST_form(self):
r = http('--form', 'http://httpbin.org/post', 'foo=bar')
self.assertIn('"foo": "bar"', r)
self.assertIn('HTTP/1.1 200', r)
def test_implicit_POST_stdin(self):
r = http('--form', 'http://httpbin.org/post',
stdin=open(TEST_FILE_PATH), stdin_isatty=False)
self.assertIn('HTTP/1.1 200', r)
class PrettyFlagTest(BaseTestCase):
"""Test the --pretty / --ugly flag handling."""
def test_pretty_enabled_by_default(self):
r = http('GET', 'http://httpbin.org/get', stdout_isatty=True)
self.assertIn(TERMINAL_COLOR_PRESENCE_CHECK, r)
def test_pretty_enabled_by_default_unless_stdin_redirected(self):
r = http('GET', 'http://httpbin.org/get', stdout_isatty=False)
self.assertNotIn(TERMINAL_COLOR_PRESENCE_CHECK, r)
def test_force_pretty(self):
r = http('--pretty', 'GET', 'http://httpbin.org/get', stdout_isatty=False)
self.assertIn(TERMINAL_COLOR_PRESENCE_CHECK, r)
def test_force_ugly(self):
r = http('--ugly', 'GET', 'http://httpbin.org/get', stdout_isatty=True)
self.assertNotIn(TERMINAL_COLOR_PRESENCE_CHECK, r)
class VerboseFlagTest(BaseTestCase):
def test_verbose(self):
r = http('--verbose', 'GET', 'http://httpbin.org/get', 'test-header:__test__')
self.assertEqual(r.count('__test__'), 2)
def test_verbose_form(self):
# https://github.com/jkbr/httpie/issues/53
r = http('--verbose', '--form', 'POST', 'http://httpbin.org/post', 'foo=bar', 'baz=bar')
self.assertIn('foo=bar&baz=bar', r)
class MultipartFormDataFileUploadTest(BaseTestCase):
def test_non_existent_file_raises_parse_error(self):
self.assertRaises(cliparse.ParseError, http,
'--form', '--traceback',
'POST', 'http://httpbin.org/post',
'foo@/__does_not_exist__')
def test_upload_ok(self):
r = http('--form', 'POST', 'http://httpbin.org/post',
'test-file@%s' % TEST_FILE_PATH, 'foo=bar')
self.assertIn('"test-file": "__test_file_content__', r)
self.assertIn('"foo": "bar"', r)
class AuthTest(BaseTestCase):
def test_basic_auth(self):
r = http('--auth', 'user:password',
'GET', 'httpbin.org/basic-auth/user/password')
self.assertIn('"authenticated": true', r)
self.assertIn('"user": "user"', r)
def test_digest_auth(self):
r = http('--auth-type=digest', '--auth', 'user:password',
'GET', 'httpbin.org/digest-auth/auth/user/password')
self.assertIn('"authenticated": true', r)
self.assertIn('"user": "user"', r)
#################################################################
# CLI argument parsing related tests.
#################################################################
class ItemParsingTest(BaseTestCase):
def setUp(self): def setUp(self):
self.key_value_type = cliparse.KeyValueType( self.key_value_type = cliparse.KeyValueType(
@@ -70,7 +224,7 @@ class TestItemParsing(BaseTest):
# data # data
self.key_value_type('baz\\=bar=foo'), self.key_value_type('baz\\=bar=foo'),
# files # files
self.key_value_type('bar\\@baz@%s' % TEST_FILE) self.key_value_type('bar\\@baz@%s' % TEST_FILE_PATH)
]) ])
self.assertDictEqual(headers, { self.assertDictEqual(headers, {
'foo:bar': 'baz', 'foo:bar': 'baz',
@@ -98,7 +252,7 @@ class TestItemParsing(BaseTest):
self.key_value_type('eh:'), self.key_value_type('eh:'),
self.key_value_type('ed='), self.key_value_type('ed='),
self.key_value_type('bool:=true'), self.key_value_type('bool:=true'),
self.key_value_type('test-file@%s' % TEST_FILE), self.key_value_type('test-file@%s' % TEST_FILE_PATH),
]) ])
self.assertDictEqual(headers, { self.assertDictEqual(headers, {
'header': 'value', 'header': 'value',
@@ -114,112 +268,77 @@ class TestItemParsing(BaseTest):
self.assertIn('test-file', files) self.assertIn('test-file', files)
class TestHTTPie(BaseTest): class HTTPieArgumentParserTestCase(unittest.TestCase):
def test_get(self): def setUp(self):
http('GET', 'http://httpbin.org/get') self.parser = cliparse.Parser()
def test_verbose(self): def test_guess_when_method_set_and_valid(self):
r = http('--verbose', 'GET', 'http://httpbin.org/get', 'test-header:__test__') args = argparse.Namespace()
self.assertEqual(r.count('__test__'), 2) args.method = 'GET'
args.url = 'http://example.com/'
args.items = []
def test_verbose_form(self): self.parser._guess_method(args)
# https://github.com/jkbr/httpie/issues/53
r = http('--verbose', '--form', 'POST', 'http://httpbin.org/post', 'foo=bar', 'baz=bar')
self.assertIn('foo=bar&baz=bar', r)
def test_json(self): self.assertEquals(args.method, 'GET')
response = http('POST', 'http://httpbin.org/post', 'foo=bar') self.assertEquals(args.url, 'http://example.com/')
self.assertIn('"foo": "bar"', response) self.assertEquals(args.items, [])
response2 = http('-j', 'GET', 'http://httpbin.org/headers')
self.assertIn('"Accept": "application/json"', response2)
response3 = http('-j', 'GET', 'http://httpbin.org/headers', 'Accept:application/xml')
self.assertIn('"Accept": "application/xml"', response3)
def test_form(self): def test_guess_when_method_not_set(self):
response = http('--form', 'POST', 'http://httpbin.org/post', 'foo=bar') args = argparse.Namespace()
self.assertIn('"foo": "bar"', response) args.method = None
args.url = 'http://example.com/'
args.items = []
def test_headers(self): self.parser._guess_method(args)
response = http('GET', 'http://httpbin.org/headers', 'Foo:bar')
self.assertIn('"User-Agent": "HTTPie', response)
self.assertIn('"Foo": "bar"', response)
self.assertEquals(args.method, 'GET')
self.assertEquals(args.url, 'http://example.com/')
self.assertEquals(args.items, [])
class TestImplicitHTTPMethod(BaseTest): def test_guess_when_method_set_but_invalid_and_data_field(self):
args = argparse.Namespace()
args.method = 'http://example.com/'
args.url = 'data=field'
args.items = []
def test_implicit_GET(self): self.parser._guess_method(args)
r = http('http://httpbin.org/get')
self.assertIn('HTTP/1.1 200', r)
def test_implicit_GET_with_headers(self): self.assertEquals(args.method, 'POST')
r = http('http://httpbin.org/headers', 'Foo:bar') self.assertEquals(args.url, 'http://example.com/')
self.assertIn('"Foo": "bar"', r) self.assertEquals(
self.assertIn('HTTP/1.1 200', r) args.items,
[cliparse.KeyValue(key='data', value='field', sep='=', orig='data=field')])
def test_implicit_POST_json(self): def test_guess_when_method_set_but_invalid_and_header_field(self):
r = http('http://httpbin.org/post', 'hello=world') args = argparse.Namespace()
self.assertIn('"hello": "world"', r) args.method = 'http://example.com/'
self.assertIn('HTTP/1.1 200', r) args.url = 'test:header'
args.items = []
def test_implicit_POST_form(self): self.parser._guess_method(args)
r = http('--form', 'http://httpbin.org/post', 'foo=bar')
self.assertIn('"foo": "bar"', r)
self.assertIn('HTTP/1.1 200', r)
def test_implicit_POST_stdin(self): self.assertEquals(args.method, 'GET')
r = http('--form', 'http://httpbin.org/post', self.assertEquals(args.url, 'http://example.com/')
stdin=open(TEST_FILE), stdin_isatty=False) self.assertEquals(
self.assertIn('HTTP/1.1 200', r) args.items,
[cliparse.KeyValue(key='test', value='header', sep=':', orig='test:header')])
def test_guess_when_method_set_but_invalid_and_item_exists(self):
args = argparse.Namespace()
args.method = 'http://example.com/'
args.url = 'new_item=a'
args.items = [
cliparse.KeyValue(key='old_item', value='b', sep='=', orig='old_item=b')
]
class TestPrettyFlag(BaseTest): self.parser._guess_method(args)
"""Test the --pretty / --ugly flag handling."""
def test_pretty_enabled_by_default(self): self.assertEquals(args.items, [
r = http('GET', 'http://httpbin.org/get', stdout_isatty=True) cliparse.KeyValue(key='new_item', value='a', sep='=', orig='new_item=a'),
self.assertIn(TERMINAL_COLOR_PRESENCE_CHECK, r) cliparse.KeyValue(key='old_item', value='b', sep='=', orig='old_item=b'),
])
def test_pretty_enabled_by_default_unless_stdin_redirected(self):
r = http('GET', 'http://httpbin.org/get', stdout_isatty=False)
self.assertNotIn(TERMINAL_COLOR_PRESENCE_CHECK, r)
def test_force_pretty(self):
r = http('--pretty', 'GET', 'http://httpbin.org/get', stdout_isatty=False)
self.assertIn(TERMINAL_COLOR_PRESENCE_CHECK, r)
def test_force_ugly(self):
r = http('--ugly', 'GET', 'http://httpbin.org/get', stdout_isatty=True)
self.assertNotIn(TERMINAL_COLOR_PRESENCE_CHECK, r)
class TestFileUpload(BaseTest):
def test_non_existent_file_raises_parse_error(self):
self.assertRaises(cliparse.ParseError, http,
'--form', '--traceback',
'POST', 'http://httpbin.org/post',
'foo@/__does_not_exist__')
def test_upload_ok(self):
r = http('--form', 'POST', 'http://httpbin.org/post',
'test-file@%s' % TEST_FILE)
self.assertIn('"test-file": "__test_file_content__', r)
class TestAuth(BaseTest):
def test_basic_auth(self):
r = http('--auth', 'user:password',
'GET', 'httpbin.org/basic-auth/user/password')
self.assertIn('"authenticated": true', r)
self.assertIn('"user": "user"', r)
def test_digest_auth(self):
r = http('--auth-type=digest', '--auth', 'user:password',
'GET', 'httpbin.org/digest-auth/auth/user/password')
self.assertIn('"authenticated": true', r)
self.assertIn('"user": "user"', r)
if __name__ == '__main__': if __name__ == '__main__':