cookiecutter

Форк
0
/
test_prompt.py 
771 строка · 27.1 Кб
1
"""Tests for `cookiecutter.prompt` module."""
2

3
import json
4
import platform
5
import sys
6
from collections import OrderedDict
7
from pathlib import Path
8

9
import click
10
import pytest
11

12
from cookiecutter import environment, exceptions, prompt
13

14

15
@pytest.fixture(autouse=True)
16
def patch_readline_on_win(monkeypatch) -> None:
17
    """Fixture. Overwrite windows end of line to linux standard."""
18
    if 'windows' in platform.platform().lower():
19
        monkeypatch.setattr('sys.stdin.readline', lambda: '\n')
20

21

22
class TestRenderVariable:
23
    """Class to unite simple and complex tests for render_variable function."""
24

25
    @pytest.mark.parametrize(
26
        'raw_var, rendered_var',
27
        [
28
            (1, '1'),
29
            (True, True),
30
            ('foo', 'foo'),
31
            ('{{cookiecutter.project}}', 'foobar'),
32
            (None, None),
33
        ],
34
    )
35
    def test_convert_to_str(self, mocker, raw_var, rendered_var) -> None:
36
        """Verify simple items correctly rendered to strings."""
37
        env = environment.StrictEnvironment()
38
        from_string = mocker.patch(
39
            'cookiecutter.utils.StrictEnvironment.from_string', wraps=env.from_string
40
        )
41
        context = {'project': 'foobar'}
42

43
        result = prompt.render_variable(env, raw_var, context)
44
        assert result == rendered_var
45

46
        # Make sure that non None non str variables are converted beforehand
47
        if raw_var is not None and not isinstance(raw_var, bool):
48
            if not isinstance(raw_var, str):
49
                raw_var = str(raw_var)
50
            from_string.assert_called_once_with(raw_var)
51
        else:
52
            assert not from_string.called
53

54
    @pytest.mark.parametrize(
55
        'raw_var, rendered_var',
56
        [
57
            ({1: True, 'foo': False}, {'1': True, 'foo': False}),
58
            (
59
                {'{{cookiecutter.project}}': ['foo', 1], 'bar': False},
60
                {'foobar': ['foo', '1'], 'bar': False},
61
            ),
62
            (['foo', '{{cookiecutter.project}}', None], ['foo', 'foobar', None]),
63
        ],
64
    )
65
    def test_convert_to_str_complex_variables(self, raw_var, rendered_var) -> None:
66
        """Verify tree items correctly rendered."""
67
        env = environment.StrictEnvironment()
68
        context = {'project': 'foobar'}
69

70
        result = prompt.render_variable(env, raw_var, context)
71
        assert result == rendered_var
72

73

74
class TestPrompt:
75
    """Class to unite user prompt related tests."""
76

77
    @pytest.mark.parametrize(
78
        'context',
79
        [
80
            {'cookiecutter': {'full_name': 'Your Name'}},
81
            {'cookiecutter': {'full_name': 'Řekni či napiš své jméno'}},
82
        ],
83
        ids=['ASCII default prompt/input', 'Unicode default prompt/input'],
84
    )
85
    def test_prompt_for_config(self, monkeypatch, context) -> None:
86
        """Verify `prompt_for_config` call `read_user_variable` on text request."""
87
        monkeypatch.setattr(
88
            'cookiecutter.prompt.read_user_variable',
89
            lambda _var, default, _prompts, _prefix: default,
90
        )
91

92
        cookiecutter_dict = prompt.prompt_for_config(context)
93
        assert cookiecutter_dict == context['cookiecutter']
94

95
    @pytest.mark.parametrize(
96
        'context',
97
        [
98
            {
99
                'cookiecutter': {
100
                    'full_name': 'Your Name',
101
                    'check': ['yes', 'no'],
102
                    'nothing': 'ok',
103
                    '__prompts__': {
104
                        'full_name': 'Name please',
105
                        'check': 'Checking',
106
                    },
107
                }
108
            },
109
        ],
110
        ids=['ASCII default prompt/input'],
111
    )
112
    def test_prompt_for_config_with_human_prompts(self, monkeypatch, context) -> None:
113
        """Verify call `read_user_variable` on request when human-readable prompts."""
114
        monkeypatch.setattr(
115
            'cookiecutter.prompt.read_user_variable',
116
            lambda _var, default, _prompts, _prefix: default,
117
        )
118
        monkeypatch.setattr(
119
            'cookiecutter.prompt.read_user_yes_no',
120
            lambda _var, default, _prompts, _prefix: default,
121
        )
122
        monkeypatch.setattr(
123
            'cookiecutter.prompt.read_user_choice',
124
            lambda _var, default, _prompts, _prefix: default,
125
        )
126

127
        cookiecutter_dict = prompt.prompt_for_config(context)
128
        assert cookiecutter_dict == context['cookiecutter']
129

130
    @pytest.mark.parametrize(
131
        'context',
132
        [
133
            {
134
                'cookiecutter': {
135
                    'full_name': 'Your Name',
136
                    'check': ['yes', 'no'],
137
                    '__prompts__': {
138
                        'check': 'Checking',
139
                    },
140
                }
141
            },
142
            {
143
                'cookiecutter': {
144
                    'full_name': 'Your Name',
145
                    'check': ['yes', 'no'],
146
                    '__prompts__': {
147
                        'full_name': 'Name please',
148
                        'check': {'__prompt__': 'Checking', 'yes': 'Yes', 'no': 'No'},
149
                    },
150
                }
151
            },
152
            {
153
                'cookiecutter': {
154
                    'full_name': 'Your Name',
155
                    'check': ['yes', 'no'],
156
                    '__prompts__': {
157
                        'full_name': 'Name please',
158
                        'check': {'no': 'No'},
159
                    },
160
                }
161
            },
162
        ],
163
    )
164
    def test_prompt_for_config_with_human_choices(self, context) -> None:
165
        """Test prompts when human-readable labels for user choices."""
166
        runner = click.testing.CliRunner()
167
        with runner.isolation(input="\n\n\n"):
168
            cookiecutter_dict = prompt.prompt_for_config(context)
169

170
        assert dict(cookiecutter_dict) == {'full_name': 'Your Name', 'check': 'yes'}
171

172
    def test_prompt_for_config_dict(self, monkeypatch) -> None:
173
        """Verify `prompt_for_config` call `read_user_variable` on dict request."""
174
        monkeypatch.setattr(
175
            'cookiecutter.prompt.read_user_dict',
176
            lambda _var, _default, _prompts, _prefix: {"key": "value", "integer": 37},
177
        )
178
        context = {'cookiecutter': {'details': {}}}
179

180
        cookiecutter_dict = prompt.prompt_for_config(context)
181
        assert cookiecutter_dict == {'details': {'key': 'value', 'integer': 37}}
182

183
    def test_should_render_dict(self) -> None:
184
        """Verify template inside dictionary variable rendered."""
185
        context = {
186
            'cookiecutter': {
187
                'project_name': 'Slartibartfast',
188
                'details': {
189
                    '{{cookiecutter.project_name}}': '{{cookiecutter.project_name}}'
190
                },
191
            }
192
        }
193

194
        cookiecutter_dict = prompt.prompt_for_config(context, no_input=True)
195
        assert cookiecutter_dict == {
196
            'project_name': 'Slartibartfast',
197
            'details': {'Slartibartfast': 'Slartibartfast'},
198
        }
199

200
    def test_should_render_deep_dict(self) -> None:
201
        """Verify nested structures like dict in dict, rendered correctly."""
202
        context = {
203
            'cookiecutter': {
204
                'project_name': "Slartibartfast",
205
                'details': {
206
                    "key": "value",
207
                    "integer_key": 37,
208
                    "other_name": '{{cookiecutter.project_name}}',
209
                    "dict_key": {
210
                        "deep_key": "deep_value",
211
                        "deep_integer": 42,
212
                        "deep_other_name": '{{cookiecutter.project_name}}',
213
                        "deep_list": [
214
                            "deep value 1",
215
                            "{{cookiecutter.project_name}}",
216
                            "deep value 3",
217
                        ],
218
                    },
219
                    "list_key": [
220
                        "value 1",
221
                        "{{cookiecutter.project_name}}",
222
                        "value 3",
223
                    ],
224
                },
225
            }
226
        }
227

228
        cookiecutter_dict = prompt.prompt_for_config(context, no_input=True)
229
        assert cookiecutter_dict == {
230
            'project_name': "Slartibartfast",
231
            'details': {
232
                "key": "value",
233
                "integer_key": "37",
234
                "other_name": "Slartibartfast",
235
                "dict_key": {
236
                    "deep_key": "deep_value",
237
                    "deep_integer": "42",
238
                    "deep_other_name": "Slartibartfast",
239
                    "deep_list": ["deep value 1", "Slartibartfast", "deep value 3"],
240
                },
241
                "list_key": ["value 1", "Slartibartfast", "value 3"],
242
            },
243
        }
244

245
    def test_should_render_deep_dict_with_human_prompts(self) -> None:
246
        """Verify dict rendered correctly when human-readable prompts."""
247
        context = {
248
            'cookiecutter': {
249
                'project_name': "Slartibartfast",
250
                'details': {
251
                    "key": "value",
252
                    "integer_key": 37,
253
                    "other_name": '{{cookiecutter.project_name}}',
254
                    "dict_key": {
255
                        "deep_key": "deep_value",
256
                    },
257
                },
258
                '__prompts__': {'project_name': 'Project name'},
259
            }
260
        }
261
        cookiecutter_dict = prompt.prompt_for_config(context, no_input=True)
262
        assert cookiecutter_dict == {
263
            'project_name': "Slartibartfast",
264
            'details': {
265
                "key": "value",
266
                "integer_key": "37",
267
                "other_name": "Slartibartfast",
268
                "dict_key": {
269
                    "deep_key": "deep_value",
270
                },
271
            },
272
        }
273

274
    def test_internal_use_no_human_prompts(self) -> None:
275
        """Verify dict rendered correctly when human-readable prompts empty."""
276
        context = {
277
            'cookiecutter': {
278
                'project_name': "Slartibartfast",
279
                '__prompts__': {},
280
            }
281
        }
282
        cookiecutter_dict = prompt.prompt_for_config(context, no_input=True)
283
        assert cookiecutter_dict == {
284
            'project_name': "Slartibartfast",
285
        }
286

287
    def test_prompt_for_templated_config(self, monkeypatch) -> None:
288
        """Verify Jinja2 templating works in unicode prompts."""
289
        monkeypatch.setattr(
290
            'cookiecutter.prompt.read_user_variable',
291
            lambda _var, default, _prompts, _prefix: default,
292
        )
293
        context = {
294
            'cookiecutter': OrderedDict(
295
                [
296
                    ('project_name', 'A New Project'),
297
                    (
298
                        'pkg_name',
299
                        '{{ cookiecutter.project_name|lower|replace(" ", "") }}',
300
                    ),
301
                ]
302
            )
303
        }
304

305
        exp_cookiecutter_dict = {
306
            'project_name': 'A New Project',
307
            'pkg_name': 'anewproject',
308
        }
309
        cookiecutter_dict = prompt.prompt_for_config(context)
310
        assert cookiecutter_dict == exp_cookiecutter_dict
311

312
    def test_dont_prompt_for_private_context_var(self, monkeypatch) -> None:
313
        """Verify `read_user_variable` not called for private context variables."""
314
        monkeypatch.setattr(
315
            'cookiecutter.prompt.read_user_variable',
316
            lambda _var, _default: pytest.fail(
317
                'Should not try to read a response for private context var'
318
            ),
319
        )
320
        context = {'cookiecutter': {'_copy_without_render': ['*.html']}}
321
        cookiecutter_dict = prompt.prompt_for_config(context)
322
        assert cookiecutter_dict == {'_copy_without_render': ['*.html']}
323

324
    def test_should_render_private_variables_with_two_underscores(self) -> None:
325
        """Test rendering of private variables with two underscores.
326

327
        There are three cases:
328
        1. Variables beginning with a single underscore are private and not rendered.
329
        2. Variables beginning with a double underscore are private and are rendered.
330
        3. Variables beginning with anything other than underscores are not private and
331
           are rendered.
332
        """
333
        context = {
334
            'cookiecutter': OrderedDict(
335
                [
336
                    ('foo', 'Hello world'),
337
                    ('bar', 123),
338
                    ('rendered_foo', '{{ cookiecutter.foo|lower }}'),
339
                    ('rendered_bar', 123),
340
                    ('_hidden_foo', '{{ cookiecutter.foo|lower }}'),
341
                    ('_hidden_bar', 123),
342
                    ('__rendered_hidden_foo', '{{ cookiecutter.foo|lower }}'),
343
                    ('__rendered_hidden_bar', 123),
344
                ]
345
            )
346
        }
347
        cookiecutter_dict = prompt.prompt_for_config(context, no_input=True)
348
        assert cookiecutter_dict == OrderedDict(
349
            [
350
                ('foo', 'Hello world'),
351
                ('bar', '123'),
352
                ('rendered_foo', 'hello world'),
353
                ('rendered_bar', '123'),
354
                ('_hidden_foo', '{{ cookiecutter.foo|lower }}'),
355
                ('_hidden_bar', 123),
356
                ('__rendered_hidden_foo', 'hello world'),
357
                ('__rendered_hidden_bar', '123'),
358
            ]
359
        )
360

361
    def test_should_not_render_private_variables(self) -> None:
362
        """Verify private(underscored) variables not rendered by `prompt_for_config`.
363

364
        Private variables designed to be raw, same as context input.
365
        """
366
        context = {
367
            'cookiecutter': {
368
                'project_name': 'Skip render',
369
                '_skip_jinja_template': '{{cookiecutter.project_name}}',
370
                '_skip_float': 123.25,
371
                '_skip_integer': 123,
372
                '_skip_boolean': True,
373
                '_skip_nested': True,
374
            }
375
        }
376
        cookiecutter_dict = prompt.prompt_for_config(context, no_input=True)
377
        assert cookiecutter_dict == context['cookiecutter']
378

379

380
DEFAULT_PREFIX = '  [dim][1/1][/] '
381

382

383
class TestReadUserChoice:
384
    """Class to unite choices prompt related tests."""
385

386
    def test_should_invoke_read_user_choice(self, mocker) -> None:
387
        """Verify correct function called for select(list) variables."""
388
        prompt_choice = mocker.patch(
389
            'cookiecutter.prompt.prompt_choice_for_config',
390
            wraps=prompt.prompt_choice_for_config,
391
        )
392

393
        read_user_choice = mocker.patch('cookiecutter.prompt.read_user_choice')
394
        read_user_choice.return_value = 'all'
395

396
        read_user_variable = mocker.patch('cookiecutter.prompt.read_user_variable')
397

398
        choices = ['landscape', 'portrait', 'all']
399
        context = {'cookiecutter': {'orientation': choices}}
400

401
        cookiecutter_dict = prompt.prompt_for_config(context)
402

403
        assert not read_user_variable.called
404
        assert prompt_choice.called
405
        read_user_choice.assert_called_once_with(
406
            'orientation', choices, {}, DEFAULT_PREFIX
407
        )
408
        assert cookiecutter_dict == {'orientation': 'all'}
409

410
    def test_should_invoke_read_user_variable(self, mocker) -> None:
411
        """Verify correct function called for string input variables."""
412
        read_user_variable = mocker.patch('cookiecutter.prompt.read_user_variable')
413
        read_user_variable.return_value = 'Audrey Roy'
414

415
        prompt_choice = mocker.patch('cookiecutter.prompt.prompt_choice_for_config')
416

417
        read_user_choice = mocker.patch('cookiecutter.prompt.read_user_choice')
418

419
        context = {'cookiecutter': {'full_name': 'Your Name'}}
420

421
        cookiecutter_dict = prompt.prompt_for_config(context)
422

423
        assert not prompt_choice.called
424
        assert not read_user_choice.called
425
        read_user_variable.assert_called_once_with(
426
            'full_name', 'Your Name', {}, DEFAULT_PREFIX
427
        )
428
        assert cookiecutter_dict == {'full_name': 'Audrey Roy'}
429

430
    def test_should_render_choices(self, mocker) -> None:
431
        """Verify Jinja2 templating engine works inside choices variables."""
432
        read_user_choice = mocker.patch('cookiecutter.prompt.read_user_choice')
433
        read_user_choice.return_value = 'anewproject'
434

435
        read_user_variable = mocker.patch('cookiecutter.prompt.read_user_variable')
436
        read_user_variable.return_value = 'A New Project'
437

438
        rendered_choices = ['foo', 'anewproject', 'bar']
439

440
        context = {
441
            'cookiecutter': OrderedDict(
442
                [
443
                    ('project_name', 'A New Project'),
444
                    (
445
                        'pkg_name',
446
                        [
447
                            'foo',
448
                            '{{ cookiecutter.project_name|lower|replace(" ", "") }}',
449
                            'bar',
450
                        ],
451
                    ),
452
                ]
453
            )
454
        }
455

456
        expected = {
457
            'project_name': 'A New Project',
458
            'pkg_name': 'anewproject',
459
        }
460
        cookiecutter_dict = prompt.prompt_for_config(context)
461

462
        read_user_variable.assert_called_once_with(
463
            'project_name', 'A New Project', {}, '  [dim][1/2][/] '
464
        )
465
        read_user_choice.assert_called_once_with(
466
            'pkg_name', rendered_choices, {}, '  [dim][2/2][/] '
467
        )
468
        assert cookiecutter_dict == expected
469

470

471
class TestPromptChoiceForConfig:
472
    """Class to unite choices prompt related tests with config test."""
473

474
    @pytest.fixture
475
    def choices(self):
476
        """Fixture. Just populate choices variable."""
477
        return ['landscape', 'portrait', 'all']
478

479
    @pytest.fixture
480
    def context(self, choices):
481
        """Fixture. Just populate context variable."""
482
        return {'cookiecutter': {'orientation': choices}}
483

484
    def test_should_return_first_option_if_no_input(
485
        self, mocker, choices, context
486
    ) -> None:
487
        """Verify prompt_choice_for_config return first list option on no_input=True."""
488
        read_user_choice = mocker.patch('cookiecutter.prompt.read_user_choice')
489

490
        expected_choice = choices[0]
491

492
        actual_choice = prompt.prompt_choice_for_config(
493
            cookiecutter_dict=context,
494
            env=environment.StrictEnvironment(),
495
            key='orientation',
496
            options=choices,
497
            no_input=True,  # Suppress user input
498
        )
499

500
        assert not read_user_choice.called
501
        assert expected_choice == actual_choice
502

503
    def test_should_read_user_choice(self, mocker, choices, context) -> None:
504
        """Verify prompt_choice_for_config return user selection on no_input=False."""
505
        read_user_choice = mocker.patch('cookiecutter.prompt.read_user_choice')
506
        read_user_choice.return_value = 'all'
507

508
        expected_choice = 'all'
509

510
        actual_choice = prompt.prompt_choice_for_config(
511
            cookiecutter_dict=context,
512
            env=environment.StrictEnvironment(),
513
            key='orientation',
514
            options=choices,
515
            no_input=False,  # Ask the user for input
516
        )
517
        read_user_choice.assert_called_once_with('orientation', choices, None, '')
518
        assert expected_choice == actual_choice
519

520

521
class TestReadUserYesNo:
522
    """Class to unite boolean prompt related tests."""
523

524
    @pytest.mark.parametrize(
525
        'run_as_docker',
526
        (
527
            True,
528
            False,
529
        ),
530
    )
531
    def test_should_invoke_read_user_yes_no(self, mocker, run_as_docker) -> None:
532
        """Verify correct function called for boolean variables."""
533
        read_user_yes_no = mocker.patch('cookiecutter.prompt.read_user_yes_no')
534
        read_user_yes_no.return_value = run_as_docker
535

536
        read_user_variable = mocker.patch('cookiecutter.prompt.read_user_variable')
537

538
        context = {'cookiecutter': {'run_as_docker': run_as_docker}}
539

540
        cookiecutter_dict = prompt.prompt_for_config(context)
541

542
        assert not read_user_variable.called
543
        read_user_yes_no.assert_called_once_with(
544
            'run_as_docker', run_as_docker, {}, DEFAULT_PREFIX
545
        )
546
        assert cookiecutter_dict == {'run_as_docker': run_as_docker}
547

548
    def test_boolean_parameter_no_input(self) -> None:
549
        """Verify boolean parameter sent to prompt for config with no input."""
550
        context = {
551
            'cookiecutter': {
552
                'run_as_docker': True,
553
            }
554
        }
555
        cookiecutter_dict = prompt.prompt_for_config(context, no_input=True)
556
        assert cookiecutter_dict == context['cookiecutter']
557

558

559
@pytest.mark.parametrize(
560
    'context',
561
    (
562
        {'cookiecutter': {'foo': '{{cookiecutter.nope}}'}},
563
        {'cookiecutter': {'foo': ['123', '{{cookiecutter.nope}}', '456']}},
564
        {'cookiecutter': {'foo': {'{{cookiecutter.nope}}': 'value'}}},
565
        {'cookiecutter': {'foo': {'key': '{{cookiecutter.nope}}'}}},
566
    ),
567
    ids=[
568
        'Undefined variable in cookiecutter dict',
569
        'Undefined variable in cookiecutter dict with choices',
570
        'Undefined variable in cookiecutter dict with dict_key',
571
        'Undefined variable in cookiecutter dict with key_value',
572
    ],
573
)
574
def test_undefined_variable(context) -> None:
575
    """Verify `prompt.prompt_for_config` raises correct error."""
576
    with pytest.raises(exceptions.UndefinedVariableInTemplate) as err:
577
        prompt.prompt_for_config(context, no_input=True)
578

579
    error = err.value
580
    assert error.message == "Unable to render variable 'foo'"
581
    assert error.context == context
582

583

584
@pytest.mark.parametrize(
585
    "template_dir,expected",
586
    [
587
        ["fake-nested-templates", "fake-project"],
588
        ["fake-nested-templates-old-style", "fake-package"],
589
    ],
590
)
591
def test_cookiecutter_nested_templates(template_dir: str, expected: str) -> None:
592
    """Test nested_templates generation."""
593
    from cookiecutter import prompt
594

595
    main_dir = (Path("tests") / template_dir).resolve()
596
    cookiecuter_context = json.loads((main_dir / "cookiecutter.json").read_text())
597
    context = {"cookiecutter": cookiecuter_context}
598
    output_dir = prompt.choose_nested_template(context, main_dir, no_input=True)
599
    expected = (Path(main_dir) / expected).resolve()
600
    assert output_dir == f"{expected}"
601

602

603
@pytest.mark.skipif(sys.platform.startswith('win'), reason="Linux / macos test")
604
@pytest.mark.parametrize(
605
    "path",
606
    [
607
        "",
608
        "/tmp",
609
        "/foo",
610
    ],
611
)
612
def test_cookiecutter_nested_templates_invalid_paths(path: str) -> None:
613
    """Test nested_templates generation."""
614
    from cookiecutter import prompt
615

616
    main_dir = (Path("tests") / "fake-nested-templates").resolve()
617
    cookiecuter_context = json.loads((main_dir / "cookiecutter.json").read_text())
618
    cookiecuter_context["templates"]["fake-project"]["path"] = path
619
    context = {"cookiecutter": cookiecuter_context}
620
    with pytest.raises(ValueError) as exc:
621
        prompt.choose_nested_template(context, main_dir, no_input=True)
622
    assert "Illegal template path" in str(exc)
623

624

625
@pytest.mark.skipif(not sys.platform.startswith('win'), reason="Win only test")
626
@pytest.mark.parametrize(
627
    "path",
628
    [
629
        "",
630
        "C:/tmp",
631
        "D:/tmp",
632
    ],
633
)
634
def test_cookiecutter_nested_templates_invalid_win_paths(path: str) -> None:
635
    """Test nested_templates generation."""
636
    from cookiecutter import prompt
637

638
    main_dir = (Path("tests") / "fake-nested-templates").resolve()
639
    cookiecuter_context = json.loads((main_dir / "cookiecutter.json").read_text())
640
    cookiecuter_context["templates"]["fake-project"]["path"] = path
641
    context = {"cookiecutter": cookiecuter_context}
642
    with pytest.raises(ValueError) as exc:
643
        prompt.choose_nested_template(context, main_dir, no_input=True)
644
    assert "Illegal template path" in str(exc)
645

646

647
def test_prompt_should_ask_and_rm_repo_dir(mocker, tmp_path) -> None:
648
    """In `prompt_and_delete()`, if the user agrees to delete/reclone the \
649
    repo, the repo should be deleted."""
650
    mock_read_user = mocker.patch(
651
        'cookiecutter.prompt.read_user_yes_no', return_value=True
652
    )
653
    repo_dir = Path(tmp_path, 'repo')
654
    repo_dir.mkdir()
655

656
    deleted = prompt.prompt_and_delete(str(repo_dir))
657

658
    assert mock_read_user.called
659
    assert not repo_dir.exists()
660
    assert deleted
661

662

663
def test_prompt_should_ask_and_exit_on_user_no_answer(mocker, tmp_path) -> None:
664
    """In `prompt_and_delete()`, if the user decline to delete/reclone the \
665
    repo, cookiecutter should exit."""
666
    mock_read_user = mocker.patch(
667
        'cookiecutter.prompt.read_user_yes_no',
668
        return_value=False,
669
    )
670
    mock_sys_exit = mocker.patch('sys.exit', return_value=True)
671
    repo_dir = Path(tmp_path, 'repo')
672
    repo_dir.mkdir()
673

674
    deleted = prompt.prompt_and_delete(str(repo_dir))
675

676
    assert mock_read_user.called
677
    assert repo_dir.exists()
678
    assert not deleted
679
    assert mock_sys_exit.called
680

681

682
def test_prompt_should_ask_and_rm_repo_file(mocker, tmp_path) -> None:
683
    """In `prompt_and_delete()`, if the user agrees to delete/reclone a \
684
    repo file, the repo should be deleted."""
685
    mock_read_user = mocker.patch(
686
        'cookiecutter.prompt.read_user_yes_no', return_value=True, autospec=True
687
    )
688

689
    repo_file = tmp_path.joinpath('repo.zip')
690
    repo_file.write_text('this is zipfile content')
691

692
    deleted = prompt.prompt_and_delete(str(repo_file))
693

694
    assert mock_read_user.called
695
    assert not repo_file.exists()
696
    assert deleted
697

698

699
def test_prompt_should_ask_and_keep_repo_on_no_reuse(mocker, tmp_path) -> None:
700
    """In `prompt_and_delete()`, if the user wants to keep their old \
701
    cloned template repo, it should not be deleted."""
702
    mock_read_user = mocker.patch(
703
        'cookiecutter.prompt.read_user_yes_no', return_value=False, autospec=True
704
    )
705
    repo_dir = Path(tmp_path, 'repo')
706
    repo_dir.mkdir()
707

708
    with pytest.raises(SystemExit):
709
        prompt.prompt_and_delete(str(repo_dir))
710

711
    assert mock_read_user.called
712
    assert repo_dir.exists()
713

714

715
def test_prompt_should_ask_and_keep_repo_on_reuse(mocker, tmp_path) -> None:
716
    """In `prompt_and_delete()`, if the user wants to keep their old \
717
    cloned template repo, it should not be deleted."""
718

719
    def answer(question, _default):
720
        return 'okay to delete' not in question
721

722
    mock_read_user = mocker.patch(
723
        'cookiecutter.prompt.read_user_yes_no', side_effect=answer, autospec=True
724
    )
725
    repo_dir = Path(tmp_path, 'repo')
726
    repo_dir.mkdir()
727

728
    deleted = prompt.prompt_and_delete(str(repo_dir))
729

730
    assert mock_read_user.called
731
    assert repo_dir.exists()
732
    assert not deleted
733

734

735
def test_prompt_should_not_ask_if_no_input_and_rm_repo_dir(mocker, tmp_path) -> None:
736
    """Prompt should not ask if no input and rm dir.
737

738
    In `prompt_and_delete()`, if `no_input` is True, the call to
739
    `prompt.read_user_yes_no()` should be suppressed.
740
    """
741
    mock_read_user = mocker.patch(
742
        'cookiecutter.prompt.read_user_yes_no', return_value=True, autospec=True
743
    )
744
    repo_dir = Path(tmp_path, 'repo')
745
    repo_dir.mkdir()
746

747
    deleted = prompt.prompt_and_delete(str(repo_dir), no_input=True)
748

749
    assert not mock_read_user.called
750
    assert not repo_dir.exists()
751
    assert deleted
752

753

754
def test_prompt_should_not_ask_if_no_input_and_rm_repo_file(mocker, tmp_path) -> None:
755
    """Prompt should not ask if no input and rm file.
756

757
    In `prompt_and_delete()`, if `no_input` is True, the call to
758
    `prompt.read_user_yes_no()` should be suppressed.
759
    """
760
    mock_read_user = mocker.patch(
761
        'cookiecutter.prompt.read_user_yes_no', return_value=True, autospec=True
762
    )
763

764
    repo_file = tmp_path.joinpath('repo.zip')
765
    repo_file.write_text('this is zipfile content')
766

767
    deleted = prompt.prompt_and_delete(str(repo_file), no_input=True)
768

769
    assert not mock_read_user.called
770
    assert not repo_file.exists()
771
    assert deleted
772

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.