httpie-cli/tests/test_cli.py

286 lines
9.9 KiB
Python
Raw Normal View History

2014-04-24 14:07:31 +02:00
"""CLI argument parsing related tests."""
import json
# noinspection PyCompatibility
import argparse
import pytest
2014-04-24 18:20:23 +02:00
from httpie import input
from httpie.input import KeyValue, KeyValueArgType
from httpie import ExitStatus
from httpie.cli import parser
from tests import TestEnvironment, http, httpbin, HTTP_OK
from tests.fixtures import (
2014-04-24 14:07:31 +02:00
FILE_PATH_ARG, JSON_FILE_PATH_ARG,
JSON_FILE_CONTENT, FILE_CONTENT, FILE_PATH
2014-04-24 14:07:31 +02:00
)
2014-04-24 14:07:31 +02:00
class TestItemParsing:
key_value_type = KeyValueArgType(*input.SEP_GROUP_ALL_ITEMS)
2014-04-24 14:07:31 +02:00
def test_invalid_items(self):
items = ['no-separator']
for item in items:
pytest.raises(argparse.ArgumentTypeError,
self.key_value_type, item)
2014-04-24 14:07:31 +02:00
def test_escape(self):
headers, data, files, params = input.parse_items([
# headers
self.key_value_type('foo\\:bar:baz'),
self.key_value_type('jack\\@jill:hill'),
# data
self.key_value_type('baz\\=bar=foo'),
# files
self.key_value_type('bar\\@baz@%s' % FILE_PATH_ARG)
])
# `requests.structures.CaseInsensitiveDict` => `dict`
headers = dict(headers._store.values())
assert headers == {
2014-04-24 14:07:31 +02:00
'foo:bar': 'baz',
'jack@jill': 'hill',
}
assert data == {'baz=bar': 'foo'}
assert 'bar@baz' in files
2014-04-24 14:07:31 +02:00
def test_escape_longsep(self):
headers, data, files, params = input.parse_items([
self.key_value_type('bob\\:==foo'),
])
assert params == {'bob:': 'foo'}
2014-04-24 14:07:31 +02:00
def test_valid_items(self):
headers, data, files, params = input.parse_items([
self.key_value_type('string=value'),
self.key_value_type('header:value'),
self.key_value_type('list:=["a", 1, {}, false]'),
self.key_value_type('obj:={"a": "b"}'),
self.key_value_type('eh:'),
self.key_value_type('ed='),
self.key_value_type('bool:=true'),
self.key_value_type('file@' + FILE_PATH_ARG),
self.key_value_type('query==value'),
self.key_value_type('string-embed=@' + FILE_PATH_ARG),
self.key_value_type('raw-json-embed:=@' + JSON_FILE_PATH_ARG),
])
# Parsed headers
# `requests.structures.CaseInsensitiveDict` => `dict`
headers = dict(headers._store.values())
assert headers == {'header': 'value', 'eh': ''}
2014-04-24 14:07:31 +02:00
# Parsed data
raw_json_embed = data.pop('raw-json-embed')
2014-04-26 18:41:28 +02:00
assert raw_json_embed == json.loads(JSON_FILE_CONTENT)
2014-04-24 14:07:31 +02:00
data['string-embed'] = data['string-embed'].strip()
assert dict(data) == {
2014-04-24 14:07:31 +02:00
"ed": "",
"string": "value",
"bool": True,
"list": ["a", 1, {}, False],
"obj": {"a": "b"},
"string-embed": FILE_CONTENT,
}
2014-04-24 14:07:31 +02:00
# Parsed query string parameters
assert params == {'query': 'value'}
2014-04-24 14:07:31 +02:00
# Parsed file fields
assert 'file' in files
assert files['file'][1].read().strip().decode('utf8') == FILE_CONTENT
2014-04-24 14:07:31 +02:00
class TestQuerystring:
2014-04-24 14:07:31 +02:00
def test_query_string_params_in_url(self):
2014-04-24 15:48:01 +02:00
r = http('--print=Hhb', 'GET', httpbin('/get?a=1&b=2'))
2014-04-24 14:07:31 +02:00
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
2014-04-24 14:07:31 +02:00
def test_query_string_params_items(self):
2014-04-24 15:48:01 +02:00
r = http('--print=Hhb', 'GET', httpbin('/get'), 'a==1', 'b==2')
2014-04-24 14:07:31 +02:00
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
2014-04-24 14:07:31 +02:00
def test_query_string_params_in_url_and_items_with_duplicates(self):
2014-04-24 15:48:01 +02:00
r = http('--print=Hhb', 'GET', httpbin('/get?a=1&a=1'),
'a==1', 'a==1', 'b==2')
2014-04-24 14:07:31 +02:00
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
2014-04-24 14:07:31 +02:00
class TestCLIParser:
2014-04-24 14:07:31 +02:00
def test_expand_localhost_shorthand(self):
args = parser.parse_args(args=[':'], env=TestEnvironment())
assert args.url == 'http://localhost'
2014-04-24 14:07:31 +02:00
def test_expand_localhost_shorthand_with_slash(self):
args = parser.parse_args(args=[':/'], env=TestEnvironment())
assert args.url == 'http://localhost/'
2014-04-24 14:07:31 +02:00
def test_expand_localhost_shorthand_with_port(self):
args = parser.parse_args(args=[':3000'], env=TestEnvironment())
assert args.url == 'http://localhost:3000'
2014-04-24 14:07:31 +02:00
def test_expand_localhost_shorthand_with_path(self):
args = parser.parse_args(args=[':/path'], env=TestEnvironment())
assert args.url == 'http://localhost/path'
2014-04-24 14:07:31 +02:00
def test_expand_localhost_shorthand_with_port_and_slash(self):
args = parser.parse_args(args=[':3000/'], env=TestEnvironment())
assert args.url == 'http://localhost:3000/'
2014-04-24 14:07:31 +02:00
def test_expand_localhost_shorthand_with_port_and_path(self):
args = parser.parse_args(args=[':3000/path'], env=TestEnvironment())
assert args.url == 'http://localhost:3000/path'
2014-04-24 14:07:31 +02:00
def test_dont_expand_shorthand_ipv6_as_shorthand(self):
args = parser.parse_args(args=['::1'], env=TestEnvironment())
assert args.url == 'http://::1'
2014-04-24 14:07:31 +02:00
def test_dont_expand_longer_ipv6_as_shorthand(self):
args = parser.parse_args(
args=['::ffff:c000:0280'],
env=TestEnvironment()
)
assert args.url == 'http://::ffff:c000:0280'
2014-04-24 14:07:31 +02:00
def test_dont_expand_full_ipv6_as_shorthand(self):
args = parser.parse_args(
args=['0000:0000:0000:0000:0000:0000:0000:0001'],
env=TestEnvironment()
)
assert args.url == 'http://0000:0000:0000:0000:0000:0000:0000:0001'
2014-04-24 14:07:31 +02:00
class TestArgumentParser:
def setup_method(self, method):
2014-04-24 14:07:31 +02:00
self.parser = input.Parser()
def test_guess_when_method_set_and_valid(self):
self.parser.args = argparse.Namespace()
self.parser.args.method = 'GET'
self.parser.args.url = 'http://example.com/'
self.parser.args.items = []
self.parser.args.ignore_stdin = False
self.parser.env = TestEnvironment()
self.parser._guess_method()
assert self.parser.args.method == 'GET'
assert self.parser.args.url == 'http://example.com/'
assert self.parser.args.items == []
2014-04-24 14:07:31 +02:00
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/'
self.parser.args.items = []
self.parser.args.ignore_stdin = False
self.parser.env = TestEnvironment()
self.parser._guess_method()
assert self.parser.args.method == 'GET'
assert self.parser.args.url == 'http://example.com/'
assert self.parser.args.items == []
2014-04-24 14:07:31 +02:00
def test_guess_when_method_set_but_invalid_and_data_field(self):
self.parser.args = argparse.Namespace()
self.parser.args.method = 'http://example.com/'
self.parser.args.url = 'data=field'
self.parser.args.items = []
self.parser.args.ignore_stdin = False
self.parser.env = TestEnvironment()
self.parser._guess_method()
assert self.parser.args.method == 'POST'
assert self.parser.args.url == 'http://example.com/'
assert self.parser.args.items == [
KeyValue(key='data',
2014-04-24 15:48:01 +02:00
value='field',
sep='=',
orig='data=field')
]
2014-04-24 14:07:31 +02:00
def test_guess_when_method_set_but_invalid_and_header_field(self):
self.parser.args = argparse.Namespace()
self.parser.args.method = 'http://example.com/'
self.parser.args.url = 'test:header'
self.parser.args.items = []
self.parser.args.ignore_stdin = False
self.parser.env = TestEnvironment()
self.parser._guess_method()
assert self.parser.args.method == 'GET'
assert self.parser.args.url == 'http://example.com/'
assert self.parser.args.items, [
KeyValue(key='test',
2014-04-24 15:48:01 +02:00
value='header',
sep=':',
orig='test:header')
]
2014-04-24 14:07:31 +02:00
def test_guess_when_method_set_but_invalid_and_item_exists(self):
self.parser.args = argparse.Namespace()
self.parser.args.method = 'http://example.com/'
self.parser.args.url = 'new_item=a'
self.parser.args.items = [
KeyValue(
2014-04-24 14:07:31 +02:00
key='old_item', value='b', sep='=', orig='old_item=b')
]
self.parser.args.ignore_stdin = False
self.parser.env = TestEnvironment()
self.parser._guess_method()
assert self.parser.args.items, [
KeyValue(key='new_item', value='a', sep='=', orig='new_item=a'),
KeyValue(
2014-04-24 14:07:31 +02:00
key='old_item', value='b', sep='=', orig='old_item=b'),
]
2014-04-24 14:07:31 +02:00
class TestNoOptions:
2014-04-24 14:07:31 +02:00
def test_valid_no_options(self):
2014-04-24 15:48:01 +02:00
r = http('--verbose', '--no-verbose', 'GET', httpbin('/get'))
assert 'GET /get HTTP/1.1' not in r
2014-04-24 14:07:31 +02:00
def test_invalid_no_options(self):
r = http('--no-war', 'GET', httpbin('/get'),
error_exit_ok=True)
assert r.exit_status == 1
assert 'unrecognized arguments: --no-war' in r.stderr
assert 'GET /get HTTP/1.1' not in r
2014-04-24 14:07:31 +02:00
class TestIgnoreStdin:
2014-04-24 14:07:31 +02:00
def test_ignore_stdin(self):
with open(FILE_PATH) as f:
2014-04-24 15:48:01 +02:00
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."
2014-04-24 14:07:31 +02:00
def test_ignore_stdin_cannot_prompt_password(self):
r = http('--ignore-stdin', '--auth=no-password', httpbin('/get'),
error_exit_ok=True)
assert r.exit_status == ExitStatus.ERROR
assert 'because --ignore-stdin' in r.stderr