Source code for tests.test_pytest

# Copyright Kevin Deldycke <kevin@deldycke.com> and contributors.
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
"""Test the Pytest helpers."""

from __future__ import annotations

import os
import re
from pathlib import Path

import click
import pytest

from click_extra import command, echo, get_cache_dir, option, strip_ansi, style
from click_extra.color import COLOR_ENVVARS
from click_extra.pytest import (
    default_debug_colored_config,
    default_debug_colored_log_end,
    default_debug_colored_log_start,
    default_debug_colored_logging,
    default_debug_colored_verbose_log,
    default_debug_colored_version_details,
    default_debug_uncolored_config,
    default_debug_uncolored_log_end,
    default_debug_uncolored_log_start,
    default_debug_uncolored_logging,
    default_debug_uncolored_verbose_log,
    default_debug_uncolored_version_details,
    default_options_colored_help,
    default_options_uncolored_help,
)
from click_extra.testing import REGEX_NEWLINE, unescape_regex


[docs] @pytest.mark.parametrize( ("uncolored", "colored"), ( (default_options_uncolored_help, default_options_colored_help), (default_debug_uncolored_logging, default_debug_colored_logging), (default_debug_uncolored_verbose_log, default_debug_colored_verbose_log), (default_debug_uncolored_config, default_debug_colored_config), ( default_debug_uncolored_version_details, default_debug_colored_version_details, ), (default_debug_uncolored_log_start, default_debug_colored_log_start), (default_debug_uncolored_log_end, default_debug_colored_log_end), ), ) def test_aligned_colored_fixtures(uncolored, colored): for uncolored_line, colored_line in zip( uncolored.split(REGEX_NEWLINE), colored.split(REGEX_NEWLINE), strict=True ): assert strip_ansi(unescape_regex(colored_line)) == unescape_regex( uncolored_line ) # Check that all lines can be compiled as regexes. assert re.compile(uncolored) assert re.compile(colored)
[docs] def test_isolated_app_dir(invoke, isolated_app_dir): """Config discovery is repointed at the isolated directory. A CLI invoked in-process must not see the host's real configuration folder, and a configuration file planted in the isolated directory must be picked up by the default ``--config`` search pattern. """ # Every application name resolves to the same isolated directory. assert Path(click.get_app_dir("any-app")) == isolated_app_dir assert Path(click.get_app_dir("other-app", roaming=False)) == isolated_app_dir @command @option("--dummy-flag/--no-flag") def my_cli(dummy_flag): echo(f"dummy_flag = {dummy_flag!r}") # The isolated directory starts empty: no configuration is discovered. result = invoke(my_cli) assert result.exit_code == 0 assert result.stdout == "dummy_flag = False\n" # A file planted in the isolated directory is discovered by default. (isolated_app_dir / "config.toml").write_text( "[my-cli]\ndummy_flag = true\n", encoding="UTF-8", ) result = invoke(my_cli) assert result.exit_code == 0 assert result.stdout == "dummy_flag = True\n"
[docs] @pytest.fixture(params=sorted(COLOR_ENVVARS)) def ambient_color_var(request, monkeypatch): """One color variable set in the caller's shell, before `runner` starts. Requested ahead of `runner` in a signature, so the variable is in place by the time the fixture isolates the environment. """ monkeypatch.setenv(request.param, "1") return request.param
[docs] def test_runner_ignores_ambient_color_vars(ambient_color_var, runner): """A color variable of the caller's shell does not reach the invoked CLI. Each one can switch the colors of the output a test matches as plain text. """ assert ambient_color_var not in os.environ @command def my_cli(): echo(style("Apricot", fg="green")) result = runner.invoke(my_cli) assert result.exit_code == 0 assert result.stdout == "Apricot\n"
[docs] @pytest.fixture def ambient_cache_home(monkeypatch, tmp_path): """A cache folder set in the caller's shell, before `runner` starts. Requested ahead of `runner` in a signature, so the variable is in place by the time the fixture isolates the environment. """ cache_home = tmp_path / "shell-cache" monkeypatch.setenv("XDG_CACHE_HOME", str(cache_home)) return cache_home
[docs] def test_runner_isolates_the_cache_dir(ambient_cache_home, runner): """The cache directory of a CLI resolves inside the isolated filesystem. The `XDG_CACHE_HOME` of the caller's shell would otherwise send every cache a CLI writes to the folder of the user running the tests. """ cache_dir = get_cache_dir("plum") assert not cache_dir.is_relative_to(ambient_cache_home) assert cache_dir.is_relative_to(Path.cwd())
[docs] def test_runner_lets_a_test_ask_for_color(runner): """A variable passed to one invocation still turns its colors on.""" @command def my_cli(): echo(style("Apricot", fg="green")) result = runner.invoke(my_cli, env={"FORCE_COLOR": "1"}) assert result.exit_code == 0 assert result.stdout != "Apricot\n" assert strip_ansi(result.stdout) == "Apricot\n"