Completed
Pull Request — master (#976)
by
unknown
31s
created

safe_force_cli_flag()   A

Complexity

Conditions 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
# -*- coding: utf-8 -*-
2
3
import os
4
import json
5
6
from click.testing import CliRunner
7
import pytest
8
9
from cookiecutter.__main__ import main
10
from cookiecutter.main import cookiecutter
11
from cookiecutter import utils
12
13
14
@pytest.fixture(scope='session')
15
def cli_runner():
16
    """Fixture that returns a helper function to run the cookiecutter cli."""
17
    runner = CliRunner()
18
19
    def cli_main(*cli_args):
20
        """Run cookiecutter cli main with the given args."""
21
        return runner.invoke(main, cli_args)
22
23
    return cli_main
24
25
26
@pytest.fixture
27
def remove_fake_project_dir(request):
28
    """
29
    Remove the fake project directory created during the tests.
30
    """
31
    def fin_remove_fake_project_dir():
32
        if os.path.isdir('fake-project'):
33
            utils.rmtree('fake-project')
34
    request.addfinalizer(fin_remove_fake_project_dir)
35
36
37
@pytest.fixture
38
def make_fake_project_dir(request):
39
    """Create a fake project to be overwritten in the according tests."""
40
    os.makedirs('fake-project')
41
42
43
@pytest.fixture(params=['-V', '--version'])
44
def version_cli_flag(request):
45
    return request.param
46
47
48
def test_cli_version(cli_runner, version_cli_flag):
49
    result = cli_runner(version_cli_flag)
50
    assert result.exit_code == 0
51
    assert result.output.startswith('Cookiecutter')
52
53
54
@pytest.mark.usefixtures('make_fake_project_dir', 'remove_fake_project_dir')
55
def test_cli_error_on_existing_output_directory(cli_runner):
56
    result = cli_runner('tests/fake-repo-pre/', '--no-input')
57
    assert result.exit_code != 0
58
    expected_error_msg = 'Error: "fake-project" directory already exists\n'
59
    assert result.output == expected_error_msg
60
61
62
@pytest.mark.usefixtures('remove_fake_project_dir')
63
def test_cli(cli_runner):
64
    result = cli_runner('tests/fake-repo-pre/', '--no-input')
65
    assert result.exit_code == 0
66
    assert os.path.isdir('fake-project')
67
    with open(os.path.join('fake-project', 'README.rst')) as f:
68
        assert 'Project name: **Fake Project**' in f.read()
69
70
71
@pytest.mark.usefixtures('remove_fake_project_dir')
72
def test_cli_verbose(cli_runner):
73
    result = cli_runner('tests/fake-repo-pre/', '--no-input', '-v')
74
    assert result.exit_code == 0
75
    assert os.path.isdir('fake-project')
76
    with open(os.path.join('fake-project', 'README.rst')) as f:
77
        assert 'Project name: **Fake Project**' in f.read()
78
79
80
@pytest.mark.usefixtures('remove_fake_project_dir')
81
def test_cli_replay(mocker, cli_runner):
82
    mock_cookiecutter = mocker.patch(
83
        'cookiecutter.cli.cookiecutter'
84
    )
85
86
    template_path = 'tests/fake-repo-pre/'
87
    result = cli_runner(template_path, '--replay', '-v')
88
89
    assert result.exit_code == 0
90
    mock_cookiecutter.assert_called_once_with(
91
        template_path,
92
        None,
93
        False,
94
        replay=True,
95
        overwrite_if_exists=False,
96
        safe_force=False,
97
        output_dir='.',
98
        config_file=None,
99
        default_config=False,
100
        extra_context=None,
101
    )
102
103
104
@pytest.mark.usefixtures('remove_fake_project_dir')
105
def test_cli_exit_on_noinput_and_replay(mocker, cli_runner):
106
    mock_cookiecutter = mocker.patch(
107
        'cookiecutter.cli.cookiecutter',
108
        side_effect=cookiecutter
109
    )
110
111
    template_path = 'tests/fake-repo-pre/'
112
    result = cli_runner(template_path, '--no-input', '--replay', '-v')
113
114
    assert result.exit_code == 1
115
116
    expected_error_msg = (
117
        "You can not use both replay and no_input or extra_context "
118
        "at the same time."
119
    )
120
121
    assert expected_error_msg in result.output
122
123
    mock_cookiecutter.assert_called_once_with(
124
        template_path,
125
        None,
126
        True,
127
        replay=True,
128
        overwrite_if_exists=False,
129
        safe_force=False,
130
        output_dir='.',
131
        config_file=None,
132
        default_config=False,
133
        extra_context=None,
134
    )
135
136
137
@pytest.fixture(params=['-f', '--overwrite-if-exists'])
138
def overwrite_cli_flag(request):
139
    return request.param
140
141
142
@pytest.mark.usefixtures('remove_fake_project_dir')
143
def test_run_cookiecutter_on_overwrite_if_exists_and_replay(
144
        mocker, cli_runner, overwrite_cli_flag):
145
    mock_cookiecutter = mocker.patch(
146
        'cookiecutter.cli.cookiecutter',
147
        side_effect=cookiecutter
148
    )
149
150
    template_path = 'tests/fake-repo-pre/'
151
    result = cli_runner(template_path, '--replay', '-v', overwrite_cli_flag)
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
        safe_force=False,
162
        output_dir='.',
163
        config_file=None,
164
        default_config=False,
165
        extra_context=None,
166
    )
167
168
169
@pytest.mark.usefixtures('remove_fake_project_dir')
170
def test_cli_overwrite_if_exists_when_output_dir_does_not_exist(
171
        cli_runner, overwrite_cli_flag):
172
173
    result = cli_runner(
174
        'tests/fake-repo-pre/',
175
        '--no-input',
176
        overwrite_cli_flag,
177
    )
178
179
    assert result.exit_code == 0
180
    assert os.path.isdir('fake-project')
181
182
183
@pytest.mark.usefixtures('make_fake_project_dir', 'remove_fake_project_dir')
184
def test_cli_overwrite_if_exists_when_output_dir_exists(
185
        cli_runner, overwrite_cli_flag):
186
187
    result = cli_runner(
188
        'tests/fake-repo-pre/',
189
        '--no-input',
190
        overwrite_cli_flag,
191
    )
192
    assert result.exit_code == 0
193
    assert os.path.isdir('fake-project')
194
195
196
@pytest.fixture(params=['--safe-force'])
197
def safe_force_cli_flag(request):
198
    return request.param
199
200
201
@pytest.mark.usefixtures('remove_fake_project_dir')
202
def test_cli_safe_force_when_output_dir_does_not_exist(
203
        mocker, cli_runner, safe_force_cli_flag):
204
    mock_cookiecutter = mocker.patch(
205
        'cookiecutter.cli.cookiecutter',
206
        side_effect=cookiecutter
207
    )
208
209
    template_path = 'tests/fake-repo-pre/'
210
    result = cli_runner(
211
        template_path,
212
        '--no-input',
213
        safe_force_cli_flag,
214
    )
215
216
    assert result.exit_code == 0
217
    assert os.path.isdir('fake-project')
218
219
    mock_cookiecutter.assert_called_once_with(
220
        template_path,
221
        None,
222
        True,
223
        replay=False,
224
        overwrite_if_exists=True,
225
        safe_force=True,
226
        output_dir='.',
227
        config_file=None,
228
        default_config=False,
229
        extra_context=None,
230
    )
231
232
233
@pytest.mark.usefixtures('make_fake_project_dir', 'remove_fake_project_dir')
234
def test_cli_safe_force_when_output_dir_exists(
235
        cli_runner, safe_force_cli_flag):
236
237
    result = cli_runner(
238
        'tests/fake-repo-pre/',
239
        '--no-input',
240
        safe_force_cli_flag,
241
    )
242
    assert result.exit_code == 0
243
    assert os.path.isdir('fake-project')
244
245
246
@pytest.fixture(params=['-o', '--output-dir'])
247
def output_dir_flag(request):
248
    return request.param
249
250
251
@pytest.fixture
252
def output_dir(tmpdir):
253
    return str(tmpdir.mkdir('output'))
254
255
256
def test_cli_output_dir(mocker, cli_runner, output_dir_flag, output_dir):
257
    mock_cookiecutter = mocker.patch(
258
        'cookiecutter.cli.cookiecutter'
259
    )
260
261
    template_path = 'tests/fake-repo-pre/'
262
    result = cli_runner(template_path, output_dir_flag, output_dir)
263
264
    assert result.exit_code == 0
265
    mock_cookiecutter.assert_called_once_with(
266
        template_path,
267
        None,
268
        False,
269
        replay=False,
270
        overwrite_if_exists=False,
271
        safe_force=False,
272
        output_dir=output_dir,
273
        config_file=None,
274
        default_config=False,
275
        extra_context=None,
276
    )
277
278
279
@pytest.fixture(params=['-h', '--help', 'help'])
280
def help_cli_flag(request):
281
    return request.param
282
283
284
def test_cli_help(cli_runner, help_cli_flag):
285
    result = cli_runner(help_cli_flag)
286
    assert result.exit_code == 0
287
    assert result.output.startswith('Usage')
288
289
290
@pytest.fixture
291
def user_config_path(tmpdir):
292
    return str(tmpdir.join('tests/config.yaml'))
293
294
295
def test_user_config(mocker, cli_runner, user_config_path):
296
    mock_cookiecutter = mocker.patch(
297
        'cookiecutter.cli.cookiecutter'
298
    )
299
300
    template_path = 'tests/fake-repo-pre/'
301
    result = cli_runner(template_path, '--config-file', user_config_path)
302
303
    assert result.exit_code == 0
304
    mock_cookiecutter.assert_called_once_with(
305
        template_path,
306
        None,
307
        False,
308
        replay=False,
309
        overwrite_if_exists=False,
310
        safe_force=False,
311
        output_dir='.',
312
        config_file=user_config_path,
313
        default_config=False,
314
        extra_context=None,
315
    )
316
317
318
def test_default_user_config_overwrite(mocker, cli_runner, user_config_path):
319
    mock_cookiecutter = mocker.patch(
320
        'cookiecutter.cli.cookiecutter'
321
    )
322
323
    template_path = 'tests/fake-repo-pre/'
324
    result = cli_runner(
325
        template_path,
326
        '--config-file',
327
        user_config_path,
328
        '--default-config',
329
    )
330
331
    assert result.exit_code == 0
332
    mock_cookiecutter.assert_called_once_with(
333
        template_path,
334
        None,
335
        False,
336
        replay=False,
337
        overwrite_if_exists=False,
338
        safe_force=False,
339
        output_dir='.',
340
        config_file=user_config_path,
341
        default_config=True,
342
        extra_context=None
343
    )
344
345
346
def test_default_user_config(mocker, cli_runner):
347
    mock_cookiecutter = mocker.patch(
348
        'cookiecutter.cli.cookiecutter'
349
    )
350
351
    template_path = 'tests/fake-repo-pre/'
352
    result = cli_runner(template_path, '--default-config')
353
354
    assert result.exit_code == 0
355
    mock_cookiecutter.assert_called_once_with(
356
        template_path,
357
        None,
358
        False,
359
        replay=False,
360
        overwrite_if_exists=False,
361
        safe_force=False,
362
        output_dir='.',
363
        config_file=None,
364
        default_config=True,
365
        extra_context=None,
366
    )
367
368
369
def test_echo_undefined_variable_error(tmpdir, cli_runner):
370
    output_dir = str(tmpdir.mkdir('output'))
371
    template_path = 'tests/undefined-variable/file-name/'
372
373
    result = cli_runner(
374
        '--no-input',
375
        '--default-config',
376
        '--output-dir',
377
        output_dir,
378
        template_path,
379
    )
380
381
    assert result.exit_code == 1
382
383
    error = "Unable to create file '{{cookiecutter.foobar}}'"
384
    assert error in result.output
385
386
    message = "Error message: 'dict object' has no attribute 'foobar'"
387
    assert message in result.output
388
389
    context = {
390
        'cookiecutter': {
391
            'github_username': 'hackebrot',
392
            'project_slug': 'testproject',
393
            '_template': template_path
394
        }
395
    }
396
    context_str = json.dumps(context, indent=4, sort_keys=True)
397
    assert context_str in result.output
398
399
400
def test_echo_unknown_extension_error(tmpdir, cli_runner):
401
    output_dir = str(tmpdir.mkdir('output'))
402
    template_path = 'tests/test-extensions/unknown/'
403
404
    result = cli_runner(
405
        '--no-input',
406
        '--default-config',
407
        '--output-dir',
408
        output_dir,
409
        template_path,
410
    )
411
412
    assert result.exit_code == 1
413
414
    assert 'Unable to load extension: ' in result.output
415
416
417
@pytest.mark.usefixtures('remove_fake_project_dir')
418
def test_cli_extra_context(cli_runner):
419
    result = cli_runner(
420
        'tests/fake-repo-pre/',
421
        '--no-input',
422
        '-v',
423
        'project_name=Awesomez',
424
    )
425
    assert result.exit_code == 0
426
    assert os.path.isdir('fake-project')
427
    with open(os.path.join('fake-project', 'README.rst')) as f:
428
        assert 'Project name: **Awesomez**' in f.read()
429
430
431
@pytest.mark.usefixtures('remove_fake_project_dir')
432
def test_cli_extra_context_invalid_format(cli_runner):
433
    result = cli_runner(
434
        'tests/fake-repo-pre/',
435
        '--no-input',
436
        '-v',
437
        'ExtraContextWithNoEqualsSoInvalid',
438
    )
439
    assert result.exit_code == 2
440
    assert 'Error: Invalid value for "extra_context"' in result.output
441
    assert 'should contain items of the form key=value' in result.output
442
443
444
@pytest.fixture
445
def debug_file(tmpdir):
446
    return tmpdir / 'fake-repo.log'
447
448
449
@pytest.mark.usefixtures('remove_fake_project_dir')
450
def test_debug_file_non_verbose(cli_runner, debug_file):
451
    assert not debug_file.exists()
452
453
    result = cli_runner(
454
        '--no-input',
455
        '--debug-file',
456
        str(debug_file),
457
        'tests/fake-repo-pre/',
458
    )
459
    assert result.exit_code == 0
460
461
    assert debug_file.exists()
462
463
    context_log = (
464
        "DEBUG cookiecutter.main: context_file is "
465
        "tests/fake-repo-pre/cookiecutter.json"
466
    )
467
    assert context_log in debug_file.readlines(cr=False)
468
    assert context_log not in result.output
469
470
471
@pytest.mark.usefixtures('remove_fake_project_dir')
472
def test_debug_file_verbose(cli_runner, debug_file):
473
    assert not debug_file.exists()
474
475
    result = cli_runner(
476
        '--verbose',
477
        '--no-input',
478
        '--debug-file',
479
        str(debug_file),
480
        'tests/fake-repo-pre/',
481
    )
482
    assert result.exit_code == 0
483
484
    assert debug_file.exists()
485
486
    context_log = (
487
        "DEBUG cookiecutter.main: context_file is "
488
        "tests/fake-repo-pre/cookiecutter.json"
489
    )
490
    assert context_log in debug_file.readlines(cr=False)
491
    assert context_log in result.output
492