1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
|
import io
import os
import sys
from pytest import skip
from pytest_relaxed import trap
from invoke.util import six
from invoke import run
from invoke._version import __version__
from invoke.terminals import WINDOWS
from _util import only_utf8
def _output_eq(cmd, expected):
assert run(cmd, hide=True).stdout == expected
def _setup(self):
self.cwd = os.getcwd()
# Enter integration/ so Invoke loads its local tasks.py
os.chdir(os.path.dirname(__file__))
class Main:
def setup(self):
# MEH
_setup(self)
def teardown(self):
os.chdir(self.cwd)
class basics:
@trap
def basic_invocation(self):
_output_eq("invoke print-foo", "foo\n")
@trap
def version_output(self):
_output_eq("invoke --version", "Invoke {}\n".format(__version__))
@trap
def help_output(self):
assert "Usage: inv[oke] " in run("invoke --help").stdout
@trap
def per_task_help(self):
assert "Frobazz" in run("invoke -c _explicit foo --help").stdout
@trap
def shorthand_binary_name(self):
_output_eq("inv print-foo", "foo\n")
@trap
def explicit_task_module(self):
_output_eq("inv --collection _explicit foo", "Yup\n")
@trap
def invocation_with_args(self):
_output_eq("inv print-name --name whatevs", "whatevs\n")
@trap
def bad_collection_exits_nonzero(self):
result = run("inv -c nope -l", warn=True)
assert result.exited == 1
assert not result.stdout
assert result.stderr
def loads_real_user_config(self):
path = os.path.expanduser("~/.invoke.yaml")
try:
with open(path, "w") as fd:
fd.write("foo: bar")
_output_eq("inv print-config", "bar\n")
finally:
try:
os.unlink(path)
except OSError:
pass
@trap
def invocable_via_python_dash_m(self):
# TODO: replace with pytest marker after pytest port
if sys.version_info < (2, 7):
skip()
_output_eq(
"python -m invoke print-name --name mainline", "mainline\n"
)
class funky_characters_in_stdout:
def setup(self):
class BadlyBehavedStdout(io.TextIOBase):
def write(self, data):
if six.PY2 and not isinstance(data, six.binary_type):
data.encode("ascii")
self.bad_stdout = BadlyBehavedStdout()
# Mehhh at 'subclassing' via inner classes =/
_setup(self)
@only_utf8
def basic_nonstandard_characters(self):
os.chdir("_support")
# Crummy "doesn't explode with decode errors" test
cmd = ("type" if WINDOWS else "cat") + " tree.out"
run(cmd, hide="stderr", out_stream=self.bad_stdout)
@only_utf8
def nonprinting_bytes(self):
# Seriously non-printing characters (i.e. non UTF8) also don't
# asplode (they would print as escapes normally, but still)
run("echo '\xff'", hide="stderr", out_stream=self.bad_stdout)
@only_utf8
def nonprinting_bytes_pty(self):
if WINDOWS:
return
# PTY use adds another utf-8 decode spot which can also fail.
run(
"echo '\xff'",
pty=True,
hide="stderr",
out_stream=self.bad_stdout,
)
class ptys:
def complex_nesting_under_ptys_doesnt_break(self):
if WINDOWS: # Not sure how to make this work on Windows
return
# GH issue 191
substr = " hello\t\t\nworld with spaces"
cmd = """ eval 'echo "{}" ' """.format(substr)
expected = " hello\t\t\r\nworld with spaces\r\n"
assert run(cmd, pty=True, hide="both").stdout == expected
def pty_puts_both_streams_in_stdout(self):
if WINDOWS:
return
os.chdir("_support")
err_echo = "{} err.py".format(sys.executable)
command = "echo foo && {} bar".format(err_echo)
r = run(command, hide="both", pty=True)
assert r.stdout == "foo\r\nbar\r\n"
assert r.stderr == ""
def simple_command_with_pty(self):
"""
Run command under PTY
"""
# Most Unix systems should have stty, which asplodes when not run
# under a pty, and prints useful info otherwise
result = run("stty -a", hide=True, pty=True)
# PTYs use \r\n, not \n, line separation
assert "\r\n" in result.stdout
assert result.pty is True
def pty_size_is_realistic(self):
# When we don't explicitly set pty size, 'stty size' sees it as
# 0x0.
# When we do set it, it should be some non 0x0, non 80x24 (the
# default) value. (yes, this means it fails if you really do have
# an 80x24 terminal. but who does that?)
size = run("stty size", hide=True, pty=True).stdout.strip()
assert size != ""
assert size != "0 0"
assert size != "24 80"
class parsing:
def false_as_optional_arg_default_value_works_okay(self):
# (Dis)proves #416. When bug present, parser gets very confused,
# asks "what the hell is 'whee'?". See also a unit test for
# Task.get_arguments.
os.chdir("_support")
for argstr, expected in (
("", "False"),
("--meh", "True"),
("--meh=whee", "whee"),
):
_output_eq(
"inv -c parsing foo {}".format(argstr), expected + "\n"
)
|