Completed
Pull Request — master (#694)
by Eric
01:25
created

TestExternalHooks.teardown_method()   C

Complexity

Conditions 8

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
c 0
b 0
f 0
dl 0
loc 17
rs 6.6666
1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
4
"""
5
test_hooks
6
------------
7
8
Tests for `cookiecutter.hooks` module.
9
"""
10
11
import sys
12
import os
13
import stat
14
import pytest
15
16
from cookiecutter import hooks, utils, exceptions
17
18
19
def make_test_repo(name):
20
    """Helper function which is called in the test setup methods."""
21
    hook_dir = os.path.join(name, 'hooks')
22
    template = os.path.join(name, 'input{{hooks}}')
23
    os.mkdir(name)
24
    os.mkdir(hook_dir)
25
    os.mkdir(template)
26
27
    with open(os.path.join(template, 'README.rst'), 'w') as f:
28
        f.write("foo\n===\n\nbar\n")
29
30
    with open(os.path.join(hook_dir, 'pre_gen_project.py'), 'w') as f:
31
        f.write("#!/usr/bin/env python\n")
32
        f.write("# -*- coding: utf-8 -*-\n")
33
        f.write("from __future__ import print_function\n")
34
        f.write("\n")
35
        f.write("print('pre generation hook')\n")
36
        f.write("f = open('python_pre.txt', 'w')\n")
37
        f.write("f.close()\n")
38
39 View Code Duplication
    with open(os.path.join(hook_dir, 'pre_user_prompt.py'), 'w') as f:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
40
        f.write("#!/usr/bin/env python\n")
41
        f.write("# -*- coding: utf-8 -*-\n")
42
        f.write("from __future__ import print_function\n")
43
        f.write("\n")
44
        f.write("print('pre user prompt hook')\n")
45
        f.write("f = open('python_pre_user_prompt.txt', 'w')\n")
46
        f.write("f.close()\n")
47
48
    if sys.platform.startswith('win'):
49
        post = 'post_gen_project.bat'
50
        with open(os.path.join(hook_dir, post), 'w') as f:
51
            f.write("@echo off\n")
52
            f.write("\n")
53
            f.write("echo post generation hook\n")
54
            f.write("echo. >shell_post.txt\n")
55
    else:
56
        post = 'post_gen_project.sh'
57
        filename = os.path.join(hook_dir, post)
58
        with open(filename, 'w') as f:
59
            f.write("#!/bin/bash\n")
60
            f.write("\n")
61
            f.write("echo 'post generation hook';\n")
62
            f.write("touch 'shell_post.txt'\n")
63
        # Set the execute bit
64
        os.chmod(filename, os.stat(filename).st_mode | stat.S_IXUSR)
65
66
    return post
67
68
69
class TestFindHooks(object):
70
71
    repo_path = 'tests/test-hooks'
72
73
    def setup_method(self, method):
74
        self.post_hook = make_test_repo(self.repo_path)
75
76
    def teardown_method(self, method):
77
        utils.rmtree(self.repo_path)
78
79
    def test_find_hook(self):
80
        """Finds the specified hook."""
81
82
        with utils.work_in(self.repo_path):
83
            expected = {
84
                'pre_gen_project': os.path.abspath('hooks/pre_gen_project.py'),
85
                'post_gen_project': os.path.abspath(
86
                    os.path.join('hooks', self.post_hook)
87
                ),
88
                'pre_user_prompt': os.path.abspath(
89
                    'hooks/pre_user_prompt.py'
90
                ),
91
            }
92
            assert expected == hooks.find_hooks()
93
94
    def test_no_hooks(self):
95
        """find_hooks should return None if the hook could not be found."""
96
97
        with utils.work_in('tests/fake-repo'):
98
            assert {} == hooks.find_hooks()
99
100
101
class TestExternalHooks(object):
102
103
    repo_path = os.path.abspath('tests/test-hooks/')
104
    hooks_path = os.path.abspath('tests/test-hooks/hooks')
105
106
    def setup_method(self, method):
107
        self.post_hook = make_test_repo(self.repo_path)
108
109
    def teardown_method(self, method):
110
        utils.rmtree(self.repo_path)
111
112
        if os.path.exists('python_pre.txt'):
113
            os.remove('python_pre.txt')
114
        if os.path.exists('python_pre_user_prompt.txt'):
115
            os.remove('python_pre_user_prompt.txt')
116
        if os.path.exists('shell_post.txt'):
117
            os.remove('shell_post.txt')
118
        if os.path.exists('tests/shell_post.txt'):
119
            os.remove('tests/shell_post.txt')
120
        if os.path.exists('tests/test-hooks/input{{hooks}}/python_pre.txt'):
121
            os.remove('tests/test-hooks/input{{hooks}}/python_pre.txt')
122
        if os.path.exists('tests/test-hooks/input{{hooks}}/shell_post.txt'):
123
            os.remove('tests/test-hooks/input{{hooks}}/shell_post.txt')
124
        if os.path.exists('tests/context_post.txt'):
125
            os.remove('tests/context_post.txt')
126
127
    def test_run_script_with_context(self):
128
        """Execute a hook script, passing a context"""
129
130
        hook_path = os.path.join(self.hooks_path, 'post_gen_project.sh')
131
132 View Code Duplication
        if sys.platform.startswith('win'):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
133
            post = 'post_gen_project.bat'
134
            with open(os.path.join(self.hooks_path, post), 'w') as f:
135
                f.write("@echo off\n")
136
                f.write("\n")
137
                f.write("echo post generation hook\n")
138
                f.write("echo. >{{cookiecutter.file}}\n")
139
        else:
140
            with open(hook_path, 'w') as fh:
141
                fh.write("#!/bin/bash\n")
142
                fh.write("\n")
143
                fh.write("echo 'post generation hook';\n")
144
                fh.write("touch 'shell_post.txt'\n")
145
                fh.write("touch '{{cookiecutter.file}}'\n")
146
                os.chmod(hook_path, os.stat(hook_path).st_mode | stat.S_IXUSR)
147
148
        hooks.run_script_with_context(
149
            os.path.join(self.hooks_path, self.post_hook),
150
            'tests',
151
            {
152
                'cookiecutter': {
153
                    'file': 'context_post.txt'
154
                }
155
            })
156
        assert os.path.isfile('tests/context_post.txt')
157
        assert 'tests' not in os.getcwd()
158
159
    def test_run_hook(self):
160
        """Execute hook from specified template in specified output
161
        directory.
162
        """
163
        tests_dir = os.path.join(self.repo_path, 'input{{hooks}}')
164
        with utils.work_in(self.repo_path):
165
            hooks.run_hook('pre_gen_project', tests_dir, {})
166
            assert os.path.isfile(os.path.join(tests_dir, 'python_pre.txt'))
167
168
            hooks.run_hook('post_gen_project', tests_dir, {})
169
            assert os.path.isfile(os.path.join(tests_dir, 'shell_post.txt'))
170
171 View Code Duplication
    def test_run_failing_hook(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
172
        hook_path = os.path.join(self.hooks_path, 'pre_gen_project.py')
173
        tests_dir = os.path.join(self.repo_path, 'input{{hooks}}')
174
175
        with open(hook_path, 'w') as f:
176
            f.write("#!/usr/bin/env python\n")
177
            f.write("import sys; sys.exit(1)\n")
178
179
        with utils.work_in(self.repo_path):
180
            with pytest.raises(exceptions.FailedHookException) as excinfo:
181
                hooks.run_hook('pre_gen_project', tests_dir, {})
182
            assert 'Hook script failed' in str(excinfo.value)
183
184 View Code Duplication
    def test_run_failing_hook_with_stderr_message(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
185
        hook_path = os.path.join(self.hooks_path, 'pre_gen_project.py')
186
        tests_dir = os.path.join(self.repo_path, 'input{{hooks}}')
187
        expected = "Expected error message"
188
189
        with open(hook_path, 'w') as f:
190
            f.write("#!/usr/bin/env python\n")
191
            f.write(
192
                "import sys; sys.stderr.write(%s) sys.exit(1)\n" % expected)
193
194
        with utils.work_in(self.repo_path):
195
            with pytest.raises(exceptions.FailedHookException) as excinfo:
196
                hooks.run_hook('pre_gen_project', tests_dir, {})
197
            assert expected in str(excinfo.value)
198