Issues (31)

tests/test_generate_hooks.py (4 issues)

1
"""Test work of python and shell hooks for generated projects."""
2
import errno
3
import os
4
import sys
5
from pathlib import Path
6
7
import pytest
8
9
from cookiecutter import generate, utils
10
from cookiecutter.exceptions import FailedHookException
11
12
WINDOWS = sys.platform.startswith('win')
13
14
15
@pytest.fixture(scope='function')
16
def remove_additional_folders(tmp_path):
17
    """Remove some special folders which are created by the tests."""
18
    yield
19
    directories_to_delete = [
20
        'tests/test-pyhooks/inputpyhooks',
21
        'inputpyhooks',
22
        'inputhooks',
23
        tmp_path.joinpath('test-shellhooks'),
24
        'tests/test-hooks',
25
    ]
26
    for directory in directories_to_delete:
27
        if os.path.exists(directory):
28
            utils.rmtree(directory)
29
30
31
@pytest.mark.usefixtures('clean_system', 'remove_additional_folders')
32
def test_ignore_hooks_dirs():
33
    """Verify hooks directory not created in target location on files generation."""
34
    generate.generate_files(
35
        context={'cookiecutter': {'pyhooks': 'pyhooks'}},
36
        repo_dir='tests/test-pyhooks/',
37
        output_dir='tests/test-pyhooks/',
38
    )
39
    assert not os.path.exists('tests/test-pyhooks/inputpyhooks/hooks')
40
41
42
@pytest.mark.usefixtures('clean_system', 'remove_additional_folders')
43
def test_run_python_hooks():
44
    """Verify pre and post generation python hooks executed and result in output_dir.
45
46
    Each hook should create in target directory. Test verifies that these files
47
    created.
48
    """
49
    generate.generate_files(
50
        context={'cookiecutter': {'pyhooks': 'pyhooks'}},
51
        repo_dir='tests/test-pyhooks/',
52
        output_dir='tests/test-pyhooks/',
53
    )
54
    assert os.path.exists('tests/test-pyhooks/inputpyhooks/python_pre.txt')
55
    assert os.path.exists('tests/test-pyhooks/inputpyhooks/python_post.txt')
56
57
58
@pytest.mark.usefixtures('clean_system', 'remove_additional_folders')
59
def test_run_python_hooks_cwd():
60
    """Verify pre and post generation python hooks executed and result in current dir.
61
62
    Each hook should create in target directory. Test verifies that these files
63
    created.
64
    """
65
    generate.generate_files(
66
        context={'cookiecutter': {'pyhooks': 'pyhooks'}}, repo_dir='tests/test-pyhooks/'
67
    )
68
    assert os.path.exists('inputpyhooks/python_pre.txt')
69
    assert os.path.exists('inputpyhooks/python_post.txt')
70
71
72
@pytest.mark.skipif(WINDOWS, reason='OSError.errno=8 is not thrown on Windows')
73
@pytest.mark.usefixtures('clean_system', 'remove_additional_folders')
74
def test_empty_hooks():
75
    """Verify error is raised on empty hook script. Ignored on windows.
76
77
    OSError.errno=8 is not thrown on Windows when the script is empty
78
    because it always runs through shell instead of needing a shebang.
79
    """
80
    with pytest.raises(FailedHookException) as excinfo:
81
        generate.generate_files(
82
            context={'cookiecutter': {'shellhooks': 'shellhooks'}},
83
            repo_dir='tests/test-shellhooks-empty/',
84
            overwrite_if_exists=True,
85
        )
86
    assert 'shebang' in str(excinfo.value)
87
88
89
@pytest.mark.usefixtures('clean_system', 'remove_additional_folders')
90
def test_oserror_hooks(mocker):
91
    """Verify script error passed correctly to cookiecutter error.
92
93
    Here subprocess.Popen function mocked, ie we do not call hook script,
94
    just produce expected error.
95
    """
96
    message = 'Out of memory'
97
98
    err = OSError(message)
99
    err.errno = errno.ENOMEM
100
101
    prompt = mocker.patch('subprocess.Popen')
102
    prompt.side_effect = err
103
104
    with pytest.raises(FailedHookException) as excinfo:
105
        generate.generate_files(
106
            context={'cookiecutter': {'shellhooks': 'shellhooks'}},
107
            repo_dir='tests/test-shellhooks-empty/',
108
            overwrite_if_exists=True,
109
        )
110
    assert message in str(excinfo.value)
111
112
113 View Code Duplication
@pytest.mark.usefixtures('clean_system', 'remove_additional_folders')
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
114
def test_run_failing_hook_removes_output_directory():
115
    """Verify project directory not created or removed if hook failed."""
116
    repo_path = os.path.abspath('tests/test-hooks/')
117
    hooks_path = os.path.abspath('tests/test-hooks/hooks')
118
119
    hook_dir = os.path.join(repo_path, 'hooks')
120
    template = os.path.join(repo_path, 'input{{cookiecutter.hooks}}')
121
    os.mkdir(repo_path)
122
    os.mkdir(hook_dir)
123
    os.mkdir(template)
124
125
    hook_path = os.path.join(hooks_path, 'pre_gen_project.py')
126
127
    with Path(hook_path).open('w') as f:
128
        f.write("#!/usr/bin/env python\n")
129
        f.write("import sys; sys.exit(1)\n")
130
131
    with pytest.raises(FailedHookException) as excinfo:
132
        generate.generate_files(
133
            context={'cookiecutter': {'hooks': 'hooks'}},
134
            repo_dir='tests/test-hooks/',
135
            overwrite_if_exists=True,
136
        )
137
138
    assert 'Hook script failed' in str(excinfo.value)
139
    assert not os.path.exists('inputhooks')
140
141
142 View Code Duplication
@pytest.mark.usefixtures('clean_system', 'remove_additional_folders')
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
143
def test_run_failing_hook_preserves_existing_output_directory():
144
    """Verify project directory not removed if exist before hook failed."""
145
    repo_path = os.path.abspath('tests/test-hooks/')
146
    hooks_path = os.path.abspath('tests/test-hooks/hooks')
147
148
    hook_dir = os.path.join(repo_path, 'hooks')
149
    template = os.path.join(repo_path, 'input{{cookiecutter.hooks}}')
150
    os.mkdir(repo_path)
151
    os.mkdir(hook_dir)
152
    os.mkdir(template)
153
154
    hook_path = os.path.join(hooks_path, 'pre_gen_project.py')
155
156
    with Path(hook_path).open('w') as f:
157
        f.write("#!/usr/bin/env python\n")
158
        f.write("import sys; sys.exit(1)\n")
159
160
    os.mkdir('inputhooks')
161
    with pytest.raises(FailedHookException) as excinfo:
162
        generate.generate_files(
163
            context={'cookiecutter': {'hooks': 'hooks'}},
164
            repo_dir='tests/test-hooks/',
165
            overwrite_if_exists=True,
166
        )
167
168
    assert 'Hook script failed' in str(excinfo.value)
169
    assert os.path.exists('inputhooks')
170
171
172 View Code Duplication
@pytest.mark.skipif(sys.platform.startswith('win'), reason="Linux only test")
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
173
@pytest.mark.usefixtures('clean_system', 'remove_additional_folders')
174
def test_run_shell_hooks(tmp_path):
175
    """Verify pre and post generate project shell hooks executed.
176
177
    This test for .sh files.
178
    """
179
    generate.generate_files(
180
        context={'cookiecutter': {'shellhooks': 'shellhooks'}},
181
        repo_dir='tests/test-shellhooks/',
182
        output_dir=tmp_path.joinpath('test-shellhooks'),
183
    )
184
    shell_pre_file = tmp_path.joinpath(
185
        'test-shellhooks', 'inputshellhooks', 'shell_pre.txt'
186
    )
187
    shell_post_file = tmp_path.joinpath(
188
        'test-shellhooks', 'inputshellhooks', 'shell_post.txt'
189
    )
190
    assert shell_pre_file.exists()
191
    assert shell_post_file.exists()
192
193
194 View Code Duplication
@pytest.mark.skipif(not sys.platform.startswith('win'), reason="Win only test")
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
195
@pytest.mark.usefixtures('clean_system', 'remove_additional_folders')
196
def test_run_shell_hooks_win(tmp_path):
197
    """Verify pre and post generate project shell hooks executed.
198
199
    This test for .bat files.
200
    """
201
    generate.generate_files(
202
        context={'cookiecutter': {'shellhooks': 'shellhooks'}},
203
        repo_dir='tests/test-shellhooks-win/',
204
        output_dir=tmp_path.joinpath('test-shellhooks-win'),
205
    )
206
    shell_pre_file = tmp_path.joinpath(
207
        'test-shellhooks-win', 'inputshellhooks', 'shell_pre.txt'
208
    )
209
    shell_post_file = tmp_path.joinpath(
210
        'test-shellhooks-win', 'inputshellhooks', 'shell_post.txt'
211
    )
212
    assert shell_pre_file.exists()
213
    assert shell_post_file.exists()
214
215
216
@pytest.mark.usefixtures("clean_system", "remove_additional_folders")
217
def test_ignore_shell_hooks(tmp_path):
218
    """Verify *.txt files not created, when accept_hooks=False."""
219
    generate.generate_files(
220
        context={"cookiecutter": {"shellhooks": "shellhooks"}},
221
        repo_dir="tests/test-shellhooks/",
222
        output_dir=tmp_path.joinpath('test-shellhooks'),
223
        accept_hooks=False,
224
    )
225
    shell_pre_file = tmp_path.joinpath("test-shellhooks/inputshellhooks/shell_pre.txt")
226
    shell_post_file = tmp_path.joinpath(
227
        "test-shellhooks/inputshellhooks/shell_post.txt"
228
    )
229
    assert not shell_pre_file.exists()
230
    assert not shell_post_file.exists()
231