test_testing.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. import os
  2. import sys
  3. from io import BytesIO
  4. import pytest
  5. import click
  6. from click.exceptions import ClickException
  7. from click.testing import CliRunner
  8. def test_runner():
  9. @click.command()
  10. def test():
  11. i = click.get_binary_stream("stdin")
  12. o = click.get_binary_stream("stdout")
  13. while True:
  14. chunk = i.read(4096)
  15. if not chunk:
  16. break
  17. o.write(chunk)
  18. o.flush()
  19. runner = CliRunner()
  20. result = runner.invoke(test, input="Hello World!\n")
  21. assert not result.exception
  22. assert result.output == "Hello World!\n"
  23. def test_echo_stdin_stream():
  24. @click.command()
  25. def test():
  26. i = click.get_binary_stream("stdin")
  27. o = click.get_binary_stream("stdout")
  28. while True:
  29. chunk = i.read(4096)
  30. if not chunk:
  31. break
  32. o.write(chunk)
  33. o.flush()
  34. runner = CliRunner(echo_stdin=True)
  35. result = runner.invoke(test, input="Hello World!\n")
  36. assert not result.exception
  37. assert result.output == "Hello World!\nHello World!\n"
  38. def test_echo_stdin_prompts():
  39. @click.command()
  40. def test_python_input():
  41. foo = input("Foo: ")
  42. click.echo(f"foo={foo}")
  43. runner = CliRunner(echo_stdin=True)
  44. result = runner.invoke(test_python_input, input="bar bar\n")
  45. assert not result.exception
  46. assert result.output == "Foo: bar bar\nfoo=bar bar\n"
  47. @click.command()
  48. @click.option("--foo", prompt=True)
  49. def test_prompt(foo):
  50. click.echo(f"foo={foo}")
  51. result = runner.invoke(test_prompt, input="bar bar\n")
  52. assert not result.exception
  53. assert result.output == "Foo: bar bar\nfoo=bar bar\n"
  54. @click.command()
  55. @click.option("--foo", prompt=True, hide_input=True)
  56. def test_hidden_prompt(foo):
  57. click.echo(f"foo={foo}")
  58. result = runner.invoke(test_hidden_prompt, input="bar bar\n")
  59. assert not result.exception
  60. assert result.output == "Foo: \nfoo=bar bar\n"
  61. @click.command()
  62. @click.option("--foo", prompt=True)
  63. @click.option("--bar", prompt=True)
  64. def test_multiple_prompts(foo, bar):
  65. click.echo(f"foo={foo}, bar={bar}")
  66. result = runner.invoke(test_multiple_prompts, input="one\ntwo\n")
  67. assert not result.exception
  68. assert result.output == "Foo: one\nBar: two\nfoo=one, bar=two\n"
  69. def test_runner_with_stream():
  70. @click.command()
  71. def test():
  72. i = click.get_binary_stream("stdin")
  73. o = click.get_binary_stream("stdout")
  74. while True:
  75. chunk = i.read(4096)
  76. if not chunk:
  77. break
  78. o.write(chunk)
  79. o.flush()
  80. runner = CliRunner()
  81. result = runner.invoke(test, input=BytesIO(b"Hello World!\n"))
  82. assert not result.exception
  83. assert result.output == "Hello World!\n"
  84. runner = CliRunner(echo_stdin=True)
  85. result = runner.invoke(test, input=BytesIO(b"Hello World!\n"))
  86. assert not result.exception
  87. assert result.output == "Hello World!\nHello World!\n"
  88. def test_prompts():
  89. @click.command()
  90. @click.option("--foo", prompt=True)
  91. def test(foo):
  92. click.echo(f"foo={foo}")
  93. runner = CliRunner()
  94. result = runner.invoke(test, input="wau wau\n")
  95. assert not result.exception
  96. assert result.output == "Foo: wau wau\nfoo=wau wau\n"
  97. @click.command()
  98. @click.option("--foo", prompt=True, hide_input=True)
  99. def test(foo):
  100. click.echo(f"foo={foo}")
  101. runner = CliRunner()
  102. result = runner.invoke(test, input="wau wau\n")
  103. assert not result.exception
  104. assert result.output == "Foo: \nfoo=wau wau\n"
  105. def test_getchar():
  106. @click.command()
  107. def continue_it():
  108. click.echo(click.getchar())
  109. runner = CliRunner()
  110. result = runner.invoke(continue_it, input="y")
  111. assert not result.exception
  112. assert result.output == "y\n"
  113. runner = CliRunner(echo_stdin=True)
  114. result = runner.invoke(continue_it, input="y")
  115. assert not result.exception
  116. assert result.output == "y\n"
  117. @click.command()
  118. def getchar_echo():
  119. click.echo(click.getchar(echo=True))
  120. runner = CliRunner()
  121. result = runner.invoke(getchar_echo, input="y")
  122. assert not result.exception
  123. assert result.output == "yy\n"
  124. runner = CliRunner(echo_stdin=True)
  125. result = runner.invoke(getchar_echo, input="y")
  126. assert not result.exception
  127. assert result.output == "yy\n"
  128. def test_catch_exceptions():
  129. class CustomError(Exception):
  130. pass
  131. @click.command()
  132. def cli():
  133. raise CustomError(1)
  134. runner = CliRunner()
  135. result = runner.invoke(cli)
  136. assert isinstance(result.exception, CustomError)
  137. assert type(result.exc_info) is tuple
  138. assert len(result.exc_info) == 3
  139. with pytest.raises(CustomError):
  140. runner.invoke(cli, catch_exceptions=False)
  141. CustomError = SystemExit
  142. result = runner.invoke(cli)
  143. assert result.exit_code == 1
  144. def test_with_color():
  145. @click.command()
  146. def cli():
  147. click.secho("hello world", fg="blue")
  148. runner = CliRunner()
  149. result = runner.invoke(cli)
  150. assert result.output == "hello world\n"
  151. assert not result.exception
  152. result = runner.invoke(cli, color=True)
  153. assert result.output == f"{click.style('hello world', fg='blue')}\n"
  154. assert not result.exception
  155. def test_with_color_errors():
  156. class CLIError(ClickException):
  157. def format_message(self) -> str:
  158. return click.style(self.message, fg="red")
  159. @click.command()
  160. def cli():
  161. raise CLIError("Red error")
  162. runner = CliRunner()
  163. result = runner.invoke(cli)
  164. assert result.output == "Error: Red error\n"
  165. assert result.exception
  166. result = runner.invoke(cli, color=True)
  167. assert result.output == f"Error: {click.style('Red error', fg='red')}\n"
  168. assert result.exception
  169. def test_with_color_but_pause_not_blocking():
  170. @click.command()
  171. def cli():
  172. click.pause()
  173. runner = CliRunner()
  174. result = runner.invoke(cli, color=True)
  175. assert not result.exception
  176. assert result.output == ""
  177. def test_exit_code_and_output_from_sys_exit():
  178. # See issue #362
  179. @click.command()
  180. def cli_string():
  181. click.echo("hello world")
  182. sys.exit("error")
  183. @click.command()
  184. @click.pass_context
  185. def cli_string_ctx_exit(ctx):
  186. click.echo("hello world")
  187. ctx.exit("error")
  188. @click.command()
  189. def cli_int():
  190. click.echo("hello world")
  191. sys.exit(1)
  192. @click.command()
  193. @click.pass_context
  194. def cli_int_ctx_exit(ctx):
  195. click.echo("hello world")
  196. ctx.exit(1)
  197. @click.command()
  198. def cli_float():
  199. click.echo("hello world")
  200. sys.exit(1.0)
  201. @click.command()
  202. @click.pass_context
  203. def cli_float_ctx_exit(ctx):
  204. click.echo("hello world")
  205. ctx.exit(1.0)
  206. @click.command()
  207. def cli_no_error():
  208. click.echo("hello world")
  209. runner = CliRunner()
  210. result = runner.invoke(cli_string)
  211. assert result.exit_code == 1
  212. assert result.output == "hello world\nerror\n"
  213. result = runner.invoke(cli_string_ctx_exit)
  214. assert result.exit_code == 1
  215. assert result.output == "hello world\nerror\n"
  216. result = runner.invoke(cli_int)
  217. assert result.exit_code == 1
  218. assert result.output == "hello world\n"
  219. result = runner.invoke(cli_int_ctx_exit)
  220. assert result.exit_code == 1
  221. assert result.output == "hello world\n"
  222. result = runner.invoke(cli_float)
  223. assert result.exit_code == 1
  224. assert result.output == "hello world\n1.0\n"
  225. result = runner.invoke(cli_float_ctx_exit)
  226. assert result.exit_code == 1
  227. assert result.output == "hello world\n1.0\n"
  228. result = runner.invoke(cli_no_error)
  229. assert result.exit_code == 0
  230. assert result.output == "hello world\n"
  231. def test_env():
  232. @click.command()
  233. def cli_env():
  234. click.echo(f"ENV={os.environ['TEST_CLICK_ENV']}")
  235. runner = CliRunner()
  236. env_orig = dict(os.environ)
  237. env = dict(env_orig)
  238. assert "TEST_CLICK_ENV" not in env
  239. env["TEST_CLICK_ENV"] = "some_value"
  240. result = runner.invoke(cli_env, env=env)
  241. assert result.exit_code == 0
  242. assert result.output == "ENV=some_value\n"
  243. assert os.environ == env_orig
  244. def test_stderr():
  245. @click.command()
  246. def cli_stderr():
  247. click.echo("stdout")
  248. click.echo("stderr", err=True)
  249. runner = CliRunner(mix_stderr=False)
  250. result = runner.invoke(cli_stderr)
  251. assert result.output == "stdout\n"
  252. assert result.stdout == "stdout\n"
  253. assert result.stderr == "stderr\n"
  254. runner_mix = CliRunner(mix_stderr=True)
  255. result_mix = runner_mix.invoke(cli_stderr)
  256. assert result_mix.output == "stdout\nstderr\n"
  257. assert result_mix.stdout == "stdout\nstderr\n"
  258. with pytest.raises(ValueError):
  259. result_mix.stderr # noqa B018
  260. @click.command()
  261. def cli_empty_stderr():
  262. click.echo("stdout")
  263. runner = CliRunner(mix_stderr=False)
  264. result = runner.invoke(cli_empty_stderr)
  265. assert result.output == "stdout\n"
  266. assert result.stdout == "stdout\n"
  267. assert result.stderr == ""
  268. @pytest.mark.parametrize(
  269. "args, expected_output",
  270. [
  271. (None, "bar\n"),
  272. ([], "bar\n"),
  273. ("", "bar\n"),
  274. (["--foo", "one two"], "one two\n"),
  275. ('--foo "one two"', "one two\n"),
  276. ],
  277. )
  278. def test_args(args, expected_output):
  279. @click.command()
  280. @click.option("--foo", default="bar")
  281. def cli_args(foo):
  282. click.echo(foo)
  283. runner = CliRunner()
  284. result = runner.invoke(cli_args, args=args)
  285. assert result.exit_code == 0
  286. assert result.output == expected_output
  287. def test_setting_prog_name_in_extra():
  288. @click.command()
  289. def cli():
  290. click.echo("ok")
  291. runner = CliRunner()
  292. result = runner.invoke(cli, prog_name="foobar")
  293. assert not result.exception
  294. assert result.output == "ok\n"
  295. def test_command_standalone_mode_returns_value():
  296. @click.command()
  297. def cli():
  298. click.echo("ok")
  299. return "Hello, World!"
  300. runner = CliRunner()
  301. result = runner.invoke(cli, standalone_mode=False)
  302. assert result.output == "ok\n"
  303. assert result.return_value == "Hello, World!"
  304. assert result.exit_code == 0
  305. def test_file_stdin_attrs(runner):
  306. @click.command()
  307. @click.argument("f", type=click.File())
  308. def cli(f):
  309. click.echo(f.name)
  310. click.echo(f.mode, nl=False)
  311. result = runner.invoke(cli, ["-"])
  312. assert result.output == "<stdin>\nr"
  313. def test_isolated_runner(runner):
  314. with runner.isolated_filesystem() as d:
  315. assert os.path.exists(d)
  316. assert not os.path.exists(d)
  317. def test_isolated_runner_custom_tempdir(runner, tmp_path):
  318. with runner.isolated_filesystem(temp_dir=tmp_path) as d:
  319. assert os.path.exists(d)
  320. assert os.path.exists(d)
  321. os.rmdir(d)
  322. def test_isolation_stderr_errors():
  323. """Writing to stderr should escape invalid characters instead of
  324. raising a UnicodeEncodeError.
  325. """
  326. runner = CliRunner(mix_stderr=False)
  327. with runner.isolation() as (_, err):
  328. click.echo("\udce2", err=True, nl=False)
  329. assert err.getvalue() == b"\\udce2"