Completed
Push — master ( 23e58c...49d409 )
by
unknown
49s
created

test_run_failing_hook_removes_output_directory()   B

Complexity

Conditions 5

Size

Total Lines 28

Duplication

Lines 27
Ratio 96.43 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 5
c 2
b 0
f 0
dl 27
loc 28
rs 8.0894
1
# -*- coding: utf-8 -*-
2
3
"""
4
test_generate_hooks
5
-------------------
6
7
Tests formerly known from a unittest residing in test_generate.py named
8
TestHooks.test_ignore_hooks_dirs
9
TestHooks.test_run_python_hooks
10
TestHooks.test_run_python_hooks_cwd
11
TestHooks.test_run_shell_hooks
12
"""
13
14
from __future__ import unicode_literals
15
import errno
16
import os
17
import sys
18
import stat
19
import pytest
20
21
from cookiecutter import generate
22
from cookiecutter import utils
23
from cookiecutter.exceptions import FailedHookException
24
25
WINDOWS = sys.platform.startswith('win')
26
27
28
@pytest.fixture(scope='function')
29
def remove_additional_folders(request):
30
    """
31
    Remove some special folders which are created by the tests.
32
    """
33
    def fin_remove_additional_folders():
34
        directories_to_delete = [
35
            'tests/test-pyhooks/inputpyhooks',
36
            'inputpyhooks',
37
            'inputhooks',
38
            'tests/test-shellhooks',
39
            'tests/test-hooks',
40
        ]
41
        for directory in directories_to_delete:
42
            if os.path.exists(directory):
43
                utils.rmtree(directory)
44
    request.addfinalizer(fin_remove_additional_folders)
45
46
47
@pytest.mark.usefixtures('clean_system', 'remove_additional_folders')
48
def test_ignore_hooks_dirs():
49
    generate.generate_files(
50
        context={
51
            'cookiecutter': {'pyhooks': 'pyhooks'}
52
        },
53
        repo_dir='tests/test-pyhooks/',
54
        output_dir='tests/test-pyhooks/'
55
    )
56
    assert not os.path.exists('tests/test-pyhooks/inputpyhooks/hooks')
57
58
59
@pytest.mark.usefixtures('clean_system', 'remove_additional_folders')
60
def test_run_python_hooks():
61
    generate.generate_files(
62
        context={
63
            'cookiecutter': {'pyhooks': 'pyhooks'}
64
        },
65
        repo_dir='tests/test-pyhooks/'.replace("/", os.sep),
66
        output_dir='tests/test-pyhooks/'.replace("/", os.sep)
67
    )
68
    assert os.path.exists('tests/test-pyhooks/inputpyhooks/python_pre.txt')
69
    assert os.path.exists('tests/test-pyhooks/inputpyhooks/python_post.txt')
70
71
72
@pytest.mark.usefixtures('clean_system', 'remove_additional_folders')
73
def test_run_python_hooks_cwd():
74
    generate.generate_files(
75
        context={
76
            'cookiecutter': {'pyhooks': 'pyhooks'}
77
        },
78
        repo_dir='tests/test-pyhooks/'
79
    )
80
    assert os.path.exists('inputpyhooks/python_pre.txt')
81
    assert os.path.exists('inputpyhooks/python_post.txt')
82
83
84
@pytest.mark.skipif(WINDOWS, reason='OSError.errno=8 is not thrown on Windows')
85
@pytest.mark.usefixtures('clean_system', 'remove_additional_folders')
86
def test_empty_hooks():
87
    # OSError.errno=8 is not thrown on Windows when the script is empty
88
    # because it always runs through shell instead of needing a shebang.
89
    with pytest.raises(FailedHookException) as excinfo:
90
        generate.generate_files(
91
            context={
92
                'cookiecutter': {'shellhooks': 'shellhooks'}
93
            },
94
            repo_dir='tests/test-shellhooks-empty/',
95
            overwrite_if_exists=True
96
        )
97
    assert 'shebang' in str(excinfo.value)
98
99
100
@pytest.mark.usefixtures('clean_system', 'remove_additional_folders')
101
def test_oserror_hooks(mocker):
102
103
    message = 'Out of memory'
104
105
    err = OSError(message)
106
    err.errno = errno.ENOMEM
107
108
    prompt = mocker.patch('subprocess.Popen')
109
    prompt.side_effect = err
110
111
    with pytest.raises(FailedHookException) as excinfo:
112
        generate.generate_files(
113
            context={
114
                'cookiecutter': {'shellhooks': 'shellhooks'}
115
            },
116
            repo_dir='tests/test-shellhooks-empty/',
117
            overwrite_if_exists=True
118
        )
119
    assert message in str(excinfo.value)
120
121
122 View Code Duplication
@pytest.mark.usefixtures('clean_system', 'remove_additional_folders')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
123
def test_run_failing_hook_removes_output_directory():
124
    repo_path = os.path.abspath('tests/test-hooks/')
125
    hooks_path = os.path.abspath('tests/test-hooks/hooks')
126
127
    hook_dir = os.path.join(repo_path, 'hooks')
128
    template = os.path.join(repo_path, 'input{{cookiecutter.hooks}}')
129
    os.mkdir(repo_path)
130
    os.mkdir(hook_dir)
131
    os.mkdir(template)
132
133
    hook_path = os.path.join(hooks_path, 'pre_gen_project.py')
134
135
    with open(hook_path, 'w') as f:
136
        f.write("#!/usr/bin/env python\n")
137
        f.write("import sys; sys.exit(1)\n")
138
139
    with pytest.raises(FailedHookException) as excinfo:
140
        generate.generate_files(
141
            context={
142
                'cookiecutter': {'hooks': 'hooks'}
143
            },
144
            repo_dir='tests/test-hooks/',
145
            overwrite_if_exists=True
146
        )
147
148
    assert 'Hook script failed' in str(excinfo.value)
149
    assert not os.path.exists('inputhooks')
150
151
152 View Code Duplication
@pytest.mark.usefixtures('clean_system', 'remove_additional_folders')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
153
def test_run_failing_hook_preserves_existing_output_directory():
154
    repo_path = os.path.abspath('tests/test-hooks/')
155
    hooks_path = os.path.abspath('tests/test-hooks/hooks')
156
157
    hook_dir = os.path.join(repo_path, 'hooks')
158
    template = os.path.join(repo_path, 'input{{cookiecutter.hooks}}')
159
    os.mkdir(repo_path)
160
    os.mkdir(hook_dir)
161
    os.mkdir(template)
162
163
    hook_path = os.path.join(hooks_path, 'pre_gen_project.py')
164
165
    with open(hook_path, 'w') as f:
166
        f.write("#!/usr/bin/env python\n")
167
        f.write("import sys; sys.exit(1)\n")
168
169
    os.mkdir('inputhooks')
170
    with pytest.raises(FailedHookException) as excinfo:
171
        generate.generate_files(
172
            context={
173
                'cookiecutter': {'hooks': 'hooks'}
174
            },
175
            repo_dir='tests/test-hooks/',
176
            overwrite_if_exists=True
177
        )
178
179
    assert 'Hook script failed' in str(excinfo.value)
180
    assert os.path.exists('inputhooks')
181
182
183
def make_test_repo(name):
184
    hooks = os.path.join(name, 'hooks')
185
    template = os.path.join(name, 'input{{cookiecutter.shellhooks}}')
186
    os.mkdir(name)
187
    os.mkdir(hooks)
188
    os.mkdir(template)
189
190
    with open(os.path.join(template, 'README.rst'), 'w') as f:
191
        f.write("foo\n===\n\nbar\n")
192
193
    if sys.platform.startswith('win'):
194
        filename = os.path.join(hooks, 'pre_gen_project.bat')
195
        with open(filename, 'w') as f:
196
            f.write("@echo off\n")
197
            f.write("\n")
198
            f.write("echo pre generation hook\n")
199
            f.write("echo. >shell_pre.txt\n")
200
201
        filename = os.path.join(hooks, 'post_gen_project.bat')
202
        with open(filename, 'w') as f:
203
            f.write("@echo off\n")
204
            f.write("\n")
205
            f.write("echo post generation hook\n")
206
            f.write("echo. >shell_post.txt\n")
207
    else:
208
        filename = os.path.join(hooks, 'pre_gen_project.sh')
209
        with open(filename, 'w') as f:
210
            f.write("#!/bin/bash\n")
211
            f.write("\n")
212
            f.write("echo 'pre generation hook';\n")
213
            f.write("touch 'shell_pre.txt'\n")
214
        # Set the execute bit
215
        os.chmod(filename, os.stat(filename).st_mode | stat.S_IXUSR)
216
217
        filename = os.path.join(hooks, 'post_gen_project.sh')
218
        with open(filename, 'w') as f:
219
            f.write("#!/bin/bash\n")
220
            f.write("\n")
221
            f.write("echo 'post generation hook';\n")
222
            f.write("touch 'shell_post.txt'\n")
223
        # Set the execute bit
224
        os.chmod(filename, os.stat(filename).st_mode | stat.S_IXUSR)
225
226
227
@pytest.mark.usefixtures('clean_system', 'remove_additional_folders')
228
def test_run_shell_hooks():
229
    make_test_repo('tests/test-shellhooks')
230
    generate.generate_files(
231
        context={
232
            'cookiecutter': {'shellhooks': 'shellhooks'}
233
        },
234
        repo_dir='tests/test-shellhooks/',
235
        output_dir='tests/test-shellhooks/'
236
    )
237
    shell_pre_file = 'tests/test-shellhooks/inputshellhooks/shell_pre.txt'
238
    shell_post_file = 'tests/test-shellhooks/inputshellhooks/shell_post.txt'
239
    assert os.path.exists(shell_pre_file)
240
    assert os.path.exists(shell_post_file)
241