Completed
Push — dry-undefined-variable-excepti... ( d183c8...3df04f )
by Michael
01:19
created

test_cli_verbose()   B

Complexity

Conditions 5

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
c 1
b 0
f 0
dl 0
loc 7
rs 8.5454
1
# -*- coding: utf-8 -*-
2
3
import os
4
import json
5
import pytest
6
7
from click.testing import CliRunner
8
9
from cookiecutter.cli import main
10
from cookiecutter.main import cookiecutter
11
from cookiecutter import utils, config
12
13
runner = CliRunner()
14
15
16
@pytest.fixture
17
def remove_fake_project_dir(request):
18
    """
19
    Remove the fake project directory created during the tests.
20
    """
21
    def fin_remove_fake_project_dir():
22
        if os.path.isdir('fake-project'):
23
            utils.rmtree('fake-project')
24
    request.addfinalizer(fin_remove_fake_project_dir)
25
26
27
@pytest.fixture
28
def make_fake_project_dir(request):
29
    """Create a fake project to be overwritten in the according tests."""
30
    os.makedirs('fake-project')
31
32
33
@pytest.fixture(params=['-V', '--version'])
34
def version_cli_flag(request):
35
    return request.param
36
37
38
def test_cli_version(version_cli_flag):
39
    result = runner.invoke(main, [version_cli_flag])
40
    assert result.exit_code == 0
41
    assert result.output.startswith('Cookiecutter')
42
43
44
@pytest.mark.usefixtures('make_fake_project_dir', 'remove_fake_project_dir')
45
def test_cli_error_on_existing_output_directory():
46
    result = runner.invoke(main, ['tests/fake-repo-pre/', '--no-input'])
47
    assert result.exit_code != 0
48
    expected_error_msg = 'Error: "fake-project" directory already exists\n'
49
    assert result.output == expected_error_msg
50
51
52
@pytest.mark.usefixtures('remove_fake_project_dir')
53
def test_cli():
54
    result = runner.invoke(main, ['tests/fake-repo-pre/', '--no-input'])
55
    assert result.exit_code == 0
56
    assert os.path.isdir('fake-project')
57
    with open(os.path.join('fake-project', 'README.rst')) as f:
58
        assert 'Project name: **Fake Project**' in f.read()
59
60
61
@pytest.mark.usefixtures('remove_fake_project_dir')
62
def test_cli_verbose():
63
    result = runner.invoke(main, ['tests/fake-repo-pre/', '--no-input', '-v'])
64
    assert result.exit_code == 0
65
    assert os.path.isdir('fake-project')
66
    with open(os.path.join('fake-project', 'README.rst')) as f:
67
        assert 'Project name: **Fake Project**' in f.read()
68
69
70
@pytest.mark.usefixtures('remove_fake_project_dir')
71
def test_cli_replay(mocker):
72
    mock_cookiecutter = mocker.patch(
73
        'cookiecutter.cli.cookiecutter'
74
    )
75
76
    template_path = 'tests/fake-repo-pre/'
77
    result = runner.invoke(main, [
78
        template_path,
79
        '--replay',
80
        '-v'
81
    ])
82
83
    assert result.exit_code == 0
84
    mock_cookiecutter.assert_called_once_with(
85
        template_path,
86
        None,
87
        False,
88
        replay=True,
89
        overwrite_if_exists=False,
90
        output_dir='.',
91
        config_file=config.USER_CONFIG_PATH,
92
        extra_context=None
93
    )
94
95
96
@pytest.mark.usefixtures('remove_fake_project_dir')
97
def test_cli_exit_on_noinput_and_replay(mocker):
98
    mock_cookiecutter = mocker.patch(
99
        'cookiecutter.cli.cookiecutter',
100
        side_effect=cookiecutter
101
    )
102
103
    template_path = 'tests/fake-repo-pre/'
104
    result = runner.invoke(main, [
105
        template_path,
106
        '--no-input',
107
        '--replay',
108
        '-v'
109
    ])
110
111
    assert result.exit_code == 1
112
113
    expected_error_msg = (
114
        "You can not use both replay and no_input or extra_context "
115
        "at the same time."
116
    )
117
118
    assert expected_error_msg in result.output
119
120
    mock_cookiecutter.assert_called_once_with(
121
        template_path,
122
        None,
123
        True,
124
        replay=True,
125
        overwrite_if_exists=False,
126
        output_dir='.',
127
        config_file=config.USER_CONFIG_PATH,
128
        extra_context=None
129
    )
130
131
132
@pytest.fixture(params=['-f', '--overwrite-if-exists'])
133
def overwrite_cli_flag(request):
134
    return request.param
135
136
137
@pytest.mark.usefixtures('remove_fake_project_dir')
138
def test_run_cookiecutter_on_overwrite_if_exists_and_replay(
139
        mocker, overwrite_cli_flag):
140
    mock_cookiecutter = mocker.patch(
141
        'cookiecutter.cli.cookiecutter',
142
        side_effect=cookiecutter
143
    )
144
145
    template_path = 'tests/fake-repo-pre/'
146
    result = runner.invoke(main, [
147
        template_path,
148
        '--replay',
149
        '-v',
150
        overwrite_cli_flag,
151
    ])
152
153
    assert result.exit_code == 0
154
155
    mock_cookiecutter.assert_called_once_with(
156
        template_path,
157
        None,
158
        False,
159
        replay=True,
160
        overwrite_if_exists=True,
161
        output_dir='.',
162
        config_file=config.USER_CONFIG_PATH,
163
        extra_context=None
164
    )
165
166
167
@pytest.mark.usefixtures('remove_fake_project_dir')
168
def test_cli_overwrite_if_exists_when_output_dir_does_not_exist(
169
        overwrite_cli_flag):
170
    result = runner.invoke(main, [
171
        'tests/fake-repo-pre/', '--no-input', overwrite_cli_flag
172
    ])
173
174
    assert result.exit_code == 0
175
    assert os.path.isdir('fake-project')
176
177
178
@pytest.mark.usefixtures('make_fake_project_dir', 'remove_fake_project_dir')
179
def test_cli_overwrite_if_exists_when_output_dir_exists(overwrite_cli_flag):
180
    result = runner.invoke(main, [
181
        'tests/fake-repo-pre/', '--no-input', overwrite_cli_flag
182
    ])
183
    assert result.exit_code == 0
184
    assert os.path.isdir('fake-project')
185
186
187
@pytest.fixture(params=['-o', '--output-dir'])
188
def output_dir_flag(request):
189
    return request.param
190
191
192
@pytest.fixture
193
def output_dir(tmpdir):
194
    return str(tmpdir.mkdir('output'))
195
196
197
def test_cli_output_dir(mocker, output_dir_flag, output_dir):
198
    mock_cookiecutter = mocker.patch(
199
        'cookiecutter.cli.cookiecutter'
200
    )
201
202
    template_path = 'tests/fake-repo-pre/'
203
    result = runner.invoke(main, [
204
        template_path,
205
        output_dir_flag,
206
        output_dir
207
    ])
208
209
    assert result.exit_code == 0
210
    mock_cookiecutter.assert_called_once_with(
211
        template_path,
212
        None,
213
        False,
214
        replay=False,
215
        overwrite_if_exists=False,
216
        output_dir=output_dir,
217
        config_file=config.USER_CONFIG_PATH,
218
        extra_context=None
219
    )
220
221
222
@pytest.fixture(params=['-h', '--help', 'help'])
223
def help_cli_flag(request):
224
    return request.param
225
226
227
def test_cli_help(help_cli_flag):
228
    result = runner.invoke(main, [help_cli_flag])
229
    assert result.exit_code == 0
230
    assert result.output.startswith('Usage')
231
232
233
@pytest.fixture
234
def user_config_path(tmpdir):
235
    return str(tmpdir.join('tests/config.yaml'))
236
237
238
def test_user_config(mocker, user_config_path):
239
    mock_cookiecutter = mocker.patch(
240
        'cookiecutter.cli.cookiecutter'
241
    )
242
243
    template_path = 'tests/fake-repo-pre/'
244
    result = runner.invoke(main, [
245
        template_path,
246
        '--config-file',
247
        user_config_path
248
    ])
249
250
    assert result.exit_code == 0
251
    mock_cookiecutter.assert_called_once_with(
252
        template_path,
253
        None,
254
        False,
255
        replay=False,
256
        overwrite_if_exists=False,
257
        output_dir='.',
258
        config_file=user_config_path,
259
        extra_context=None
260
    )
261
262
263
def test_default_user_config_overwrite(mocker, user_config_path):
264
    mock_cookiecutter = mocker.patch(
265
        'cookiecutter.cli.cookiecutter'
266
    )
267
268
    template_path = 'tests/fake-repo-pre/'
269
    result = runner.invoke(main, [
270
        template_path,
271
        '--config-file',
272
        user_config_path,
273
        '--default-config'
274
    ])
275
276
    assert result.exit_code == 0
277
    mock_cookiecutter.assert_called_once_with(
278
        template_path,
279
        None,
280
        False,
281
        replay=False,
282
        overwrite_if_exists=False,
283
        output_dir='.',
284
        config_file=None,
285
        extra_context=None
286
    )
287
288
289
def test_default_user_config(mocker):
290
    mock_cookiecutter = mocker.patch(
291
        'cookiecutter.cli.cookiecutter'
292
    )
293
294
    template_path = 'tests/fake-repo-pre/'
295
    result = runner.invoke(main, [
296
        template_path,
297
        '--default-config'
298
    ])
299
300
    assert result.exit_code == 0
301
    mock_cookiecutter.assert_called_once_with(
302
        template_path,
303
        None,
304
        False,
305
        replay=False,
306
        overwrite_if_exists=False,
307
        output_dir='.',
308
        config_file=None,
309
        extra_context=None
310
    )
311
312
313
def test_echo_undefined_variable_error(tmpdir):
314
    output_dir = str(tmpdir.mkdir('output'))
315
    template_path = 'tests/undefined-variable/file-name/'
316
317
    result = runner.invoke(main, [
318
        '--no-input',
319
        '--default-config',
320
        '--output-dir',
321
        output_dir,
322
        template_path,
323
    ])
324
325
    assert result.exit_code == 1
326
327
    error = "Unable to create file '{{cookiecutter.foobar}}'"
328
    assert error in result.output
329
330
    message = "Error message: 'dict object' has no attribute 'foobar'"
331
    assert message in result.output
332
333
    context = {
334
        'cookiecutter': {
335
            'github_username': 'hackebrot',
336
            'project_slug': 'testproject'
337
        }
338
    }
339
    context_str = json.dumps(context, indent=4, sort_keys=True)
340
    assert context_str in result.output
341
342
343
def test_echo_unknown_extension_error(tmpdir):
344
    output_dir = str(tmpdir.mkdir('output'))
345
    template_path = 'tests/test-extensions/unknown/'
346
347
    result = runner.invoke(main, [
348
        '--no-input',
349
        '--default-config',
350
        '--output-dir',
351
        output_dir,
352
        template_path,
353
    ])
354
355
    assert result.exit_code == 1
356
357
    assert 'Unable to load extension: ' in result.output
358
359
360
@pytest.mark.usefixtures('remove_fake_project_dir')
361
def test_cli_extra_context():
362
    result = runner.invoke(main, ['tests/fake-repo-pre/', '--no-input', '-v',
363
                                  'project_name=Awesomez'])
364
    assert result.exit_code == 0
365
    assert os.path.isdir('fake-project')
366
    with open(os.path.join('fake-project', 'README.rst')) as f:
367
        assert 'Project name: **Awesomez**' in f.read()
368
369
370
@pytest.mark.usefixtures('remove_fake_project_dir')
371
def test_cli_extra_context_invalid_format():
372
    result = runner.invoke(main, ['tests/fake-repo-pre/', '--no-input', '-v',
373
                                  'ExtraContextWithNoEqualsSoInvalid'])
374
    assert result.exit_code == 2
375
    assert 'Error: Invalid value for "extra_context"' in result.output
376
    assert 'should contain items of the form key=value' in result.output
377