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