def test_should_render_deep_dict_with_human_prompts(self):
        """Verify dict rendered correctly when human-readable prompts."""
        context = {
            'cookiecutter': {
                'project_name': "Slartibartfast",
                'details': {
                    "key": "value",
                    "integer_key": 37,
                    "other_name": '{{cookiecutter.project_name}}',
                    "dict_key": {
                        "deep_key": "deep_value",
                    },
                },
                '__prompts__': {'project_name': 'Project name'},
            }
        }
        cookiecutter_dict = prompt.prompt_for_config(context, no_input=True)
        assert cookiecutter_dict == {
            'project_name': "Slartibartfast",
            'details': {
                "key": "value",
                "integer_key": "37",
                "other_name": "Slartibartfast",
                "dict_key": {
                    "deep_key": "deep_value",
                },
            },
        }

    def test_internal_use_no_human_prompts(self):
        """Verify dict rendered correctly when human-readable prompts empty."""
        context = {
            'cookiecutter': {
                'project_name': "Slartibartfast",
                '__prompts__': {},
            }
        }
        cookiecutter_dict = prompt.prompt_for_config(context, no_input=True)
        assert cookiecutter_dict == {
            'project_name': "Slartibartfast",
        }

    def test_prompt_for_templated_config(self, monkeypatch):
        """Verify Jinja2 templating works in unicode prompts."""
        monkeypatch.setattr(
            'cookiecutter.prompt.read_user_variable',
            lambda var, default, prompts, prefix: default,
        )
        context = {
            'cookiecutter': OrderedDict(
                [
                    ('project_name', 'A New Project'),
                    (
                        'pkg_name',
                        '{{ cookiecutter.project_name|lower|replace(" ", "") }}',
                    ),
                ]
            )
        }

        exp_cookiecutter_dict = {
            'project_name': 'A New Project',
            'pkg_name': 'anewproject',
        }
        cookiecutter_dict = prompt.prompt_for_config(context)
        assert cookiecutter_dict == exp_cookiecutter_dict

    def test_dont_prompt_for_private_context_var(self, monkeypatch):
        """Verify `read_user_variable` not called for private context variables."""
        monkeypatch.setattr(
            'cookiecutter.prompt.read_user_variable',
            lambda var, default: pytest.fail(
                'Should not try to read a response for private context var'
            ),
        )
        context = {'cookiecutter': {'_copy_without_render': ['*.html']}}
        cookiecutter_dict = prompt.prompt_for_config(context)
        assert cookiecutter_dict == {'_copy_without_render': ['*.html']}

    def test_should_render_private_variables_with_two_underscores(self):
        """Test rendering of private variables with two underscores.

        There are three cases:
        1. Variables beginning with a single underscore are private and not rendered.
        2. Variables beginning with a double underscore are private and are rendered.
        3. Variables beginning with anything other than underscores are not private and
           are rendered.
        """
        context = {
            'cookiecutter': OrderedDict(
                [
                    ('foo', 'Hello world'),
                    ('bar', 123),
                    ('rendered_foo', '{{ cookiecutter.foo|lower }}'),
                    ('rendered_bar', 123),
                    ('_hidden_foo', '{{ cookiecutter.foo|lower }}'),
                    ('_hidden_bar', 123),
                    ('__rendered_hidden_foo', '{{ cookiecutter.foo|lower }}'),
                    ('__rendered_hidden_bar', 123),
                ]
            )
        }
        cookiecutter_dict = prompt.prompt_for_config(context, no_input=True)
        assert cookiecutter_dict == OrderedDict(
            [
                ('foo', 'Hello world'),
                ('bar', '123'),
                ('rendered_foo', 'hello world'),
                ('rendered_bar', '123'),
                ('_hidden_foo', '{{ cookiecutter.foo|lower }}'),
                ('_hidden_bar', 123),
                ('__rendered_hidden_foo', 'hello world'),
                ('__rendered_hidden_bar', '123'),
            ]
        )

    def test_should_not_render_private_variables(self):
        """Verify private(underscored) variables not rendered by `prompt_for_config`.

        Private variables designed to be raw, same as context input.
        """
        context = {
            'cookiecutter': {
                'project_name': 'Skip render',
                '_skip_jinja_template': '{{cookiecutter.project_name}}',
                '_skip_float': 123.25,
                '_skip_integer': 123,
                '_skip_boolean': True,
                '_skip_nested': True,
            }
        }
        cookiecutter_dict = prompt.prompt_for_config(context, no_input=True)
        assert cookiecutter_dict == context['cookiecutter']


DEFAULT_PREFIX = '  [dim][1/1][/] '


class TestReadUserChoice:
    """Class to unite choices prompt related tests."""

    def test_should_invoke_read_user_choice(self, mocker):
        """Verify correct function called for select(list) variables."""
        prompt_choice = mocker.patch(
            'cookiecutter.prompt.prompt_choice_for_config',
            wraps=prompt.prompt_choice_for_config,
        )

        read_user_choice = mocker.patch('cookiecutter.prompt.read_user_choice')
        read_user_choice.return_value = 'all'

        read_user_variable = mocker.patch('cookiecutter.prompt.read_user_variable')

        choices = ['landscape', 'portrait', 'all']
        context = {'cookiecutter': {'orientation': choices}}

        cookiecutter_dict = prompt.prompt_for_config(context)

        assert not read_user_variable.called
        assert prompt_choice.called
        read_user_choice.assert_called_once_with(
            'orientation', choices, {}, DEFAULT_PREFIX
        )
        assert cookiecutter_dict == {'orientation': 'all'}

    def test_should_invoke_read_user_variable(self, mocker):
        """Verify correct function called for string input variables."""
        read_user_variable = mocker.patch('cookiecutter.prompt.read_user_variable')
        read_user_variable.return_value = 'Audrey Roy'

        prompt_choice = mocker.patch('cookiecutter.prompt.prompt_choice_for_config')

        read_user_choice = mocker.patch('cookiecutter.prompt.read_user_choice')

        context = {'cookiecutter': {'full_name': 'Your Name'}}

        cookiecutter_dict = prompt.prompt_for_config(context)

        assert not prompt_choice.called
        assert not read_user_choice.called
        read_user_variable.assert_called_once_with(
            'full_name', 'Your Name', {}, DEFAULT_PREFIX
        )
        assert cookiecutter_dict == {'full_name': 'Audrey Roy'}

    def test_should_render_choices(self, mocker):
        """Verify Jinja2 templating engine works inside choices variables."""
        read_user_choice = mocker.patch('cookiecutter.prompt.read_user_choice')
        read_user_choice.return_value = 'anewproject'

        read_user_variable = mocker.patch('cookiecutter.prompt.read_user_variable')
        read_user_variable.return_value = 'A New Project'

        rendered_choices = ['foo', 'anewproject', 'bar']

        context = {
            'cookiecutter': OrderedDict(
                [
                    ('project_name', 'A New Project'),
                    (
                        'pkg_name',
                        [
                            'foo',
                            '{{ cookiecutter.project_name|lower|replace(" ", "") }}',
                            'bar',
                        ],
                    ),
                ]
            )
        }

        expected = {
            'project_name': 'A New Project',
            'pkg_name': 'anewproject',
        }
        cookiecutter_dict = prompt.prompt_for_config(context)

        read_user_variable.assert_called_once_with(
            'project_name', 'A New Project', {}, '  [dim][1/2][/] '
        )
        read_user_choice.assert_called_once_with(
            'pkg_name', rendered_choices, {}, '  [dim][2/2][/] '
        )
        assert cookiecutter_dict == expected


class TestPromptChoiceForConfig:
    """Class to unite choices prompt related tests with config test."""

    @pytest.fixture
    def choices(self):
        """Fixture. Just populate choices variable."""
        return ['landscape', 'portrait', 'all']

    @pytest.fixture
    def context(self, choices):
        """Fixture. Just populate context variable."""
        return {'cookiecutter': {'orientation': choices}}

    def test_should_return_first_option_if_no_input(self, mocker, choices, context):
        """Verify prompt_choice_for_config return first list option on no_input=True."""
        read_user_choice = mocker.patch('cookiecutter.prompt.read_user_choice')

        expected_choice = choices[0]

        actual_choice = prompt.prompt_choice_for_config(
            cookiecutter_dict=context,
            env=environment.StrictEnvironment(),
            key='orientation',
            options=choices,
            no_input=True,  # Suppress user input
        )

        assert not read_user_choice.called
        assert expected_choice == actual_choice

    def test_should_read_user_choice(self, mocker, choices, context):
        """Verify prompt_choice_for_config return user selection on no_input=False."""
        read_user_choice = mocker.patch('cookiecutter.prompt.read_user_choice')
        read_user_choice.return_value = 'all'

        expected_choice = 'all'

        actual_choice = prompt.prompt_choice_for_config(
            cookiecutter_dict=context,
            env=environment.StrictEnvironment(),
            key='orientation',
            options=choices,
            no_input=False,  # Ask the user for input
        )
        read_user_choice.assert_called_once_with('orientation', choices, None, '')
        assert expected_choice == actual_choice


class TestReadUserYesNo(object):
    """Class to unite boolean prompt related tests."""

    @pytest.mark.parametrize(
        'run_as_docker',
        (
            True,
            False,
        ),
    )
    def test_should_invoke_read_user_yes_no(self, mocker, run_as_docker):
        """Verify correct function called for boolean variables."""
        read_user_yes_no = mocker.patch('cookiecutter.prompt.read_user_yes_no')
        read_user_yes_no.return_value = run_as_docker

        read_user_variable = mocker.patch('cookiecutter.prompt.read_user_variable')

        context = {'cookiecutter': {'run_as_docker': run_as_docker}}

        cookiecutter_dict = prompt.prompt_for_config(context)

        assert not read_user_variable.called
        read_user_yes_no.assert_called_once_with(
            'run_as_docker', run_as_docker, {}, DEFAULT_PREFIX
        )
        assert cookiecutter_dict == {'run_as_docker': run_as_docker}

    def test_boolean_parameter_no_input(self):
        """Verify boolean parameter sent to prompt for config with no input."""
        context = {
            'cookiecutter': {
                'run_as_docker': True,
            }
        }
        cookiecutter_dict = prompt.prompt_for_config(context, no_input=True)
        assert cookiecutter_dict == context['cookiecutter']


@pytest.mark.parametrize(
    'context',
    (
        {'cookiecutter': {'foo': '{{cookiecutter.nope}}'}},
        {'cookiecutter': {'foo': ['123', '{{cookiecutter.nope}}', '456']}},
        {'cookiecutter': {'foo': {'{{cookiecutter.nope}}': 'value'}}},
        {'cookiecutter': {'foo': {'key': '{{cookiecutter.nope}}'}}},
    ),
    ids=[
        'Undefined variable in cookiecutter dict',
        'Undefined variable in cookiecutter dict with choices',
        'Undefined variable in cookiecutter dict with dict_key',
        'Undefined variable in cookiecutter dict with key_value',
    ],
)
def test_undefined_variable(context):
    """Verify `prompt.prompt_for_config` raises correct error."""
    with pytest.raises(exceptions.UndefinedVariableInTemplate) as err:
        prompt.prompt_for_config(context, no_input=True)

    error = err.value
    assert error.message == "Unable to render variable 'foo'"
    assert error.context == context


@pytest.mark.parametrize(
    "template_dir,expected",
    [
        ["fake-nested-templates", "fake-project"],
        ["fake-nested-templates-old-style", "fake-package"],
    ],
)
def test_cookiecutter_nested_templates(template_dir: str, expected: str):
    """Test nested_templates generation."""
    from cookiecutter import prompt

    main_dir = (Path("tests") / template_dir).resolve()
    cookiecuter_context = json.loads((main_dir / "cookiecutter.json").read_text())
    context = {"cookiecutter": cookiecuter_context}
    output_dir = prompt.choose_nested_template(context, main_dir, no_input=True)
    expected = (Path(main_dir) / expected).resolve()
    assert output_dir == f"{expected}"


@pytest.mark.skipif(sys.platform.startswith('win'), reason="Linux / macos test")
@pytest.mark.parametrize(
    "path",
    [
        "",
        "/tmp",
        "/foo",
    ],
)
def test_cookiecutter_nested_templates_invalid_paths(path: str):
    """Test nested_templates generation."""
    from cookiecutter import prompt

    main_dir = (Path("tests") / "fake-nested-templates").resolve()
    cookiecuter_context = json.loads((main_dir / "cookiecutter.json").read_text())
    cookiecuter_context["templates"]["fake-project"]["path"] = path
    context = {"cookiecutter": cookiecuter_context}
    with pytest.raises(ValueError) as exc:
        prompt.choose_nested_template(context, main_dir, no_input=True)
    assert "Illegal template path" in str(exc)


@pytest.mark.skipif(not sys.platform.startswith('win'), reason="Win only test")
@pytest.mark.parametrize(
    "path",
    [
        "",
        "C:/tmp",
        "D:/tmp",
    ],
)
def test_cookiecutter_nested_templates_invalid_win_paths(path: str):
    """Test nested_templates generation."""
    from cookiecutter import prompt

    main_dir = (Path("tests") / "fake-nested-templates").resolve()
    cookiecuter_context = json.loads((main_dir / "cookiecutter.json").read_text())
    cookiecuter_context["templates"]["fake-project"]["path"] = path
    context = {"cookiecutter": cookiecuter_context}
    with pytest.raises(ValueError) as exc:
        prompt.choose_nested_template(context, main_dir, no_input=True)
    assert "Illegal template path" in str(exc)


def test_prompt_should_ask_and_rm_repo_dir(mocker, tmp_path):
    """In `prompt_and_delete()`, if the user agrees to del<response clipped><NOTE>Due to the max output limit, only part of the full response has been shown to you.</NOTE>iecutter import exceptions, repository


@pytest.fixture
def template():
    """Fixture. Return simple string as template name."""
    return 'cookiecutter-pytest-plugin'


@pytest.fixture
def cloned_cookiecutter_path(user_config_data, template):
    """Fixture. Prepare folder structure for tests in this file."""
    cookiecutters_dir = user_config_data['cookiecutters_dir']

    cloned_template_path = os.path.join(cookiecutters_dir, template)
    if not os.path.exists(cloned_template_path):
        os.mkdir(cloned_template_path)  # might exist from other tests.

    subdir_template_path = os.path.join(cloned_template_path, 'my-dir')
    if not os.path.exists(subdir_template_path):
        os.mkdir(subdir_template_path)
    Path(subdir_template_path, 'cookiecutter.json').touch()  # creates file

    return subdir_template_path


def test_should_find_existing_cookiecutter(
    template, user_config_data, cloned_cookiecutter_path
):
    """Find `cookiecutter.json` in sub folder created by `cloned_cookiecutter_path`."""
    project_dir, cleanup = repository.determine_repo_dir(
        template=template,
        abbreviations={},
        clone_to_dir=user_config_data['cookiecutters_dir'],
        checkout=None,
        no_input=True,
        directory='my-dir',
    )

    assert cloned_cookiecutter_path == project_dir
    assert not cleanup


def test_local_repo_typo(template, user_config_data, cloned_cookiecutter_path):
    """Wrong pointing to `cookiecutter.json` sub-directory should raise."""
    with pytest.raises(exceptions.RepositoryNotFound) as err:
        repository.determine_repo_dir(
            template=template,
            abbreviations={},
            clone_to_dir=user_config_data['cookiecutters_dir'],
            checkout=None,
            no_input=True,
            directory='wrong-dir',
        )

    wrong_full_cookiecutter_path = os.path.join(
        os.path.dirname(cloned_cookiecutter_path), 'wrong-dir'
    )
    assert str(err.value) == (
        'A valid repository for "{}" could not be found in the following '
        'locations:\n{}'.format(
            template,
            '\n'.join(
                [os.path.join(template, 'wrong-dir'), wrong_full_cookiecutter_path]
            ),
        )
    )
--- tests/repository/test_determine_repository_should_use_local_repo.py
"""Tests around using locally cached cookiecutter template repositories."""

from pathlib import Path

import pytest

from cookiecutter import exceptions, repository


def test_finds_local_repo(tmp_path):
    """A valid local repository should be returned."""
    project_dir, cleanup = repository.determine_repo_dir(
        'tests/fake-repo',
        abbreviations={},
        clone_to_dir=str(tmp_path),
        checkout=None,
        no_input=True,
    )

    assert 'tests/fake-repo' == project_dir
    assert not cleanup


def test_local_repo_with_no_context_raises(tmp_path):
    """A local repository without a cookiecutter.json should raise a \
    `RepositoryNotFound` exception."""
    template_path = str(Path('tests', 'fake-repo-bad'))
    with pytest.raises(exceptions.RepositoryNotFound) as err:
        repository.determine_repo_dir(
            template_path,
            abbreviations={},
            clone_to_dir=str(tmp_path),
            checkout=None,
            no_input=True,
        )

    assert str(err.value) == (
        'A valid repository for "{}" could not be found in the following '
        'locations:\n{}'.format(
            template_path,
            '\n'.join(
                [template_path, str(tmp_path.joinpath('tests', 'fake-repo-bad'))]
            ),
        )
    )


def test_local_repo_typo(tmp_path):
    """An unknown local repository should raise a `RepositoryNotFound` \
    exception."""
    template_path = str(Path('tests', 'unknown-repo'))
    with pytest.raises(exceptions.RepositoryNotFound) as err:
        repository.determine_repo_dir(
            template_path,
            abbreviations={},
            clone_to_dir=str(tmp_path),
            checkout=None,
            no_input=True,
        )

    assert str(err.value) == (
        'A valid repository for "{}" could not be found in the following '
        'locations:\n{}'.format(
            template_path,
            '\n'.join([template_path, str(tmp_path.joinpath('tests', 'unknown-repo'))]),
        )
    )
--- tests/repository/test_is_repo_url.py
"""Tests for all supported cookiecutter template repository locations."""

import pytest

from cookiecutter.config import BUILTIN_ABBREVIATIONS
from cookiecutter.repository import expand_abbreviations, is_repo_url, is_zip_file


@pytest.fixture(
    params=[
        '/path/to/zipfile.zip',
        'https://example.com/path/to/zipfile.zip',
        'http://example.com/path/to/zipfile.zip',
    ]
)
def zipfile(request):
    """Fixture. Represent possible paths to zip file."""
    return request.param


def test_is_zip_file(zipfile):
    """Verify is_repo_url works."""
    assert is_zip_file(zipfile) is True


@pytest.fixture(
    params=[
        'gitolite@server:team/repo',
        'git@github.com:audreyfeldroy/cookiecutter.git',
        'https://github.com/cookiecutter/cookiecutter.git',
        'git+https://private.com/gitrepo',
        'hg+https://private.com/mercurialrepo',
        'https://bitbucket.org/pokoli/cookiecutter.hg',
        'file://server/path/to/repo.git',
    ]
)
def remote_repo_url(request):
    """Fixture. Represent possible URI to different repositories types."""
    return request.param


def test_is_repo_url_for_remote_urls(remote_repo_url):
    """Verify is_repo_url works."""
    assert is_repo_url(remote_repo_url) is True


@pytest.fixture(
    params=[
        '/audreyr/cookiecutter.git',
        '/home/audreyr/cookiecutter',
        (
            'c:\\users\\foo\\appdata\\local\\temp\\1\\pytest-0\\'
            'test_default_output_dir0\\template'
        ),
    ]
)
def local_repo_url(request):
    """Fixture. Represent possible paths to local resources."""
    return request.param


def test_is_repo_url_for_local_urls(local_repo_url):
    """Verify is_repo_url works."""
    assert is_repo_url(local_repo_url) is False


def test_expand_abbreviations():
    """Validate `repository.expand_abbreviations` correctly translate url."""
    template = 'gh:audreyfeldroy/cookiecutter-pypackage'

    # This is not a valid repo url just yet!
    # First `repository.expand_abbreviations` needs to translate it
    assert is_repo_url(template) is False

    expanded_template = expand_abbreviations(template, BUILTIN_ABBREVIATIONS)
    assert is_repo_url(expanded_template) is True
--- tests/repository/test_repository_has_cookiecutter_json.py
"""Tests for `repository_has_cookiecutter_json` function."""

import pytest

from cookiecutter.repository import repository_has_cookiecutter_json


def test_valid_repository():
    """Validate correct response if `cookiecutter.json` file exist."""
    assert repository_has_cookiecutter_json('tests/fake-repo')


@pytest.mark.parametrize(
    'invalid_repository', (['tests/fake-repo-bad', 'tests/unknown-repo'])
)
def test_invalid_repository(invalid_repository):
    """Validate correct response if `cookiecutter.json` file not exist."""
    assert not repository_has_cookiecutter_json(invalid_repository)

### replay
--- tests/replay/test_dump.py
"""test_dump."""

import json
import os

import pytest

from cookiecutter import replay


@pytest.fixture
def template_name():
    """Fixture to return a valid template_name."""
    return 'cookiedozer'


@pytest.fixture
def replay_file(replay_test_dir, template_name):
    """Fixture to return a actual file name of the dump."""
    file_name = f'{template_name}.json'
    return os.path.join(replay_test_dir, file_name)


@pytest.fixture(autouse=True)
def remove_replay_dump(request, replay_file):
    """Remove the replay file created by tests."""

    def fin_remove_replay_file():
        if os.path.exists(replay_file):
            os.remove(replay_file)

    request.addfinalizer(fin_remove_replay_file)


def test_type_error_if_no_template_name(replay_test_dir, context):
    """Test that replay.dump raises if the template_name is not a valid str."""
    with pytest.raises(TypeError):
        replay.dump(replay_test_dir, None, context)


def test_type_error_if_not_dict_context(replay_test_dir, template_name):
    """Test that replay.dump raises if the context is not of type dict."""
    with pytest.raises(TypeError):
        replay.dump(replay_test_dir, template_name, 'not_a_dict')


def test_value_error_if_key_missing_in_context(replay_test_dir, template_name):
    """Test that replay.dump raises if the context does not contain a key \
    named 'cookiecutter'."""
    with pytest.raises(ValueError):
        replay.dump(replay_test_dir, template_name, {'foo': 'bar'})


@pytest.fixture
def mock_ensure_failure(mocker):
    """Replace cookiecutter.replay.make_sure_path_exists function.

    Used to mock internal function and limit test scope.
    Always return expected value: False
    """
    return mocker.patch(
        'cookiecutter.replay.make_sure_path_exists', side_effect=OSError
    )


@pytest.fixture
def mock_ensure_success(mocker):
    """Replace cookiecutter.replay.make_sure_path_exists function.

    Used to mock internal function and limit test scope.
    Always return expected value: True
    """
    return mocker.patch('cookiecutter.replay.make_sure_path_exists', return_value=True)


def test_ioerror_if_replay_dir_creation_fails(mock_ensure_failure, replay_test_dir):
    """Test that replay.dump raises when the replay_dir cannot be created."""
    with pytest.raises(OSError):
        replay.dump(replay_test_dir, 'foo', {'cookiecutter': {'hello': 'world'}})

    mock_ensure_failure.assert_called_once_with(replay_test_dir)


def test_run_json_dump(
    mocker,
    mock_ensure_success,
    mock_user_config,
    template_name,
    context,
    replay_test_dir,
    replay_file,
):
    """Test that replay.dump runs json.dump under the hood and that the context \
    is correctly written to the expected file in the replay_dir."""
    spy_get_replay_file = mocker.spy(replay, 'get_file_name')

    mock_json_dump = mocker.patch('json.dump', side_effect=json.dump)

    replay.dump(replay_test_dir, template_name, context)

    assert not mock_user_config.called
    mock_ensure_success.assert_called_once_with(replay_test_dir)
    spy_get_replay_file.assert_called_once_with(replay_test_dir, template_name)

    assert mock_json_dump.call_count == 1
    (dumped_context, outfile_handler), kwargs = mock_json_dump.call_args
    assert outfile_handler.name == replay_file
    assert dumped_context == context
--- tests/replay/test_load.py
"""test_load."""

import json
import os

import pytest

from cookiecutter import replay


@pytest.fixture
def template_name():
    """Fixture to return a valid template_name."""
    return 'cookiedozer_load'


@pytest.fixture
def replay_file(replay_test_dir, template_name):
    """Fixture to return a actual file name of the dump."""
    file_name = f'{template_name}.json'
    return os.path.join(replay_test_dir, file_name)


def test_type_error_if_no_template_name(replay_test_dir):
    """Test that replay.load raises if the template_name is not a valid str."""
    with pytest.raises(TypeError):
        replay.load(replay_test_dir, None)


def test_value_error_if_key_missing_in_context(mocker, replay_test_dir):
    """Test that replay.load raises if the loaded context does not contain \
    'cookiecutter'."""
    with pytest.raises(ValueError):
        replay.load(replay_test_dir, 'invalid_replay')


def test_io_error_if_no_replay_file(mocker, replay_test_dir):
    """Test that replay.load raises if it cannot find a replay file."""
    with pytest.raises(IOError):
        replay.load(replay_test_dir, 'no_replay')


def test_run_json_load(
    mocker, mock_user_config, template_name, context, replay_test_dir, replay_file
):
    """Test that replay.load runs json.load under the hood and that the context \
    is correctly loaded from the file in replay_dir."""
    spy_get_replay_file = mocker.spy(replay, 'get_file_name')

    mock_json_load = mocker.patch('json.load', side_effect=json.load)

    loaded_context = replay.load(replay_test_dir, template_name)

    assert not mock_user_config.called
    spy_get_replay_file.assert_called_once_with(replay_test_dir, template_name)

    assert mock_json_load.call_count == 1
    (infile_handler,), kwargs = mock_json_load.call_args
    assert infile_handler.name == replay_file
    assert loaded_context == context
--- tests/replay/test_replay.py
"""test_replay."""

import os

import pytest

from cookiecutter import exceptions, main, replay


@pytest.mark.parametrize("replay_file_name", ['bar', 'bar.json'])
def test_get_replay_file_name(replay_file_name):
    """Make sure that replay.get_file_name generates a valid json file path."""
    exp_replay_file_path = os.path.join('foo', 'bar.json')
    replay_file_path = replay.get_file_name('foo', replay_file_name)
    assert replay_file_path == exp_replay_file_path


@pytest.mark.parametrize(
    'invalid_kwargs',
    (
        {'no_input': True},
        {'extra_context': {}},
        {'no_input': True, 'extra_context': {}},
    ),
)
def test_raise_on_invalid_mode(invalid_kwargs):
    """Test `cookiecutter` raise exception on unacceptable `replay` request."""
    with pytest.raises(exceptions.InvalidModeException):
        main.cookiecutter('foo', replay=True, **invalid_kwargs)


def test_main_does_not_invoke_dump_but_load(mocker):
    """Test `cookiecutter` calling correct functions on `replay`."""
    mock_prompt = mocker.patch('cookiecutter.main.prompt_for_config')
    mock_gen_context = mocker.patch('cookiecutter.main.generate_context')
    mock_gen_files = mocker.patch('cookiecutter.main.generate_files')
    mock_replay_dump = mocker.patch('cookiecutter.main.dump')
    mock_replay_load = mocker.patch('cookiecutter.main.load')

    main.cookiecutter('tests/fake-repo-tmpl/', replay=True)

    assert not mock_prompt.called
    assert mock_gen_context.called
    assert mock_replay_dump.called
    assert mock_replay_load.called
    assert mock_gen_files.called


def test_main_does_not_invoke_load_but_dump(mocker):
    """Test `cookiecutter` calling correct functions on non-replay launch."""
    mock_prompt = mocker.patch('cookiecutter.main.prompt_for_config')
    mock_gen_context = mocker.patch('cookiecutter.main.generate_context')
    mock_gen_files = mocker.patch('cookiecutter.main.generate_files')
    mock_replay_dump = mocker.patch('cookiecutter.main.dump')
    mock_replay_load = mocker.patch('cookiecutter.main.load')

    main.cookiecutter('tests/fake-repo-tmpl/', replay=False)

    assert mock_prompt.called
    assert mock_gen_context.called
    assert mock_replay_dump.called
    assert not mock_replay_load.called
    assert mock_gen_files.called
[The command completed with exit code 0.]
[Current working directory: /workspace/cookiecutter]
[Python interpreter: /usr/bin/python]
[Command finished with exit code 0]