Passed
Push — master ( b1f642...d6037b )
by
unknown
01:06
created

tests.test_utils.test_work_in_without_path()   A

Complexity

Conditions 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 2
nop 0
1
"""Tests for `cookiecutter.utils` module."""
2
import stat
3
import sys
4
from pathlib import Path
5
6
import pytest
7
8
from cookiecutter import utils
9
10
11
def make_readonly(path):
12
    """Change the access permissions to readonly for a given file."""
13
    mode = Path.stat(path).st_mode
14
    Path.chmod(path, mode & ~stat.S_IWRITE)
15
16
17
def test_force_delete(mocker, tmp_path):
18
    """Verify `utils.force_delete` makes files writable."""
19
    ro_file = Path(tmp_path, 'bar')
20
21
    with open(ro_file, "w") as f:
22
        f.write("Test data")
23
    make_readonly(ro_file)
24
25
    rmtree = mocker.Mock()
26
    utils.force_delete(rmtree, ro_file, sys.exc_info())
27
28
    assert (ro_file.stat().st_mode & stat.S_IWRITE) == stat.S_IWRITE
29
    rmtree.assert_called_once_with(ro_file)
30
31
    utils.rmtree(tmp_path)
32
33
34
def test_rmtree(tmp_path):
35
    """Verify `utils.rmtree` remove files marked as read-only."""
36
    with open(Path(tmp_path, 'bar'), "w") as f:
37
        f.write("Test data")
38
    make_readonly(Path(tmp_path, 'bar'))
39
40
    utils.rmtree(tmp_path)
41
42
    assert not Path(tmp_path).exists()
43
44
45
def test_make_sure_path_exists(tmp_path):
46
    """Verify correct True/False response from `utils.make_sure_path_exists`.
47
48
    Should return True if directory exist or created.
49
    Should return False if impossible to create directory (for example protected)
50
    """
51
    existing_directory = tmp_path
52
    directory_to_create = Path(tmp_path, "not_yet_created")
53
54
    assert utils.make_sure_path_exists(existing_directory)
55
    assert utils.make_sure_path_exists(directory_to_create)
56
57
    # Ensure by base system methods.
58
    assert existing_directory.is_dir()
59
    assert existing_directory.exists()
60
    assert directory_to_create.is_dir()
61
    assert directory_to_create.exists()
62
63
64
def test_make_sure_path_exists_correctly_handle_os_error(mocker):
65
    """Verify correct True/False response from `utils.make_sure_path_exists`.
66
67
    Should return True if directory exist or created.
68
    Should return False if impossible to create directory (for example protected)
69
    """
70
71
    def raiser(*args, **kwargs):
72
        raise OSError()
73
74
    mocker.patch("os.makedirs", raiser)
75
    uncreatable_directory = Path('protected_path')
76
77
    assert not utils.make_sure_path_exists(uncreatable_directory)
78
79
80
def test_work_in(tmp_path):
81
    """Verify returning to original folder after `utils.work_in` use."""
82
    cwd = Path.cwd()
83
    ch_to = tmp_path
84
85
    assert ch_to != Path.cwd()
86
87
    # Under context manager we should work in tmp_path.
88
    with utils.work_in(ch_to):
89
        assert ch_to == Path.cwd()
90
91
    # Make sure we return to the correct folder
92
    assert cwd == Path.cwd()
93
94
95
def test_work_in_without_path():
96
    """Folder is not changed if no path provided."""
97
    cwd = Path.cwd()
98
99
    with utils.work_in():
100
        assert cwd == Path.cwd()
101
102
    assert cwd == Path.cwd()
103
104
105
def test_prompt_should_ask_and_rm_repo_dir(mocker, tmp_path):
106
    """In `prompt_and_delete()`, if the user agrees to delete/reclone the \
107
    repo, the repo should be deleted."""
108
    mock_read_user = mocker.patch(
109
        'cookiecutter.utils.read_user_yes_no', return_value=True
110
    )
111
    repo_dir = Path(tmp_path, 'repo')
112
    repo_dir.mkdir()
113
114
    deleted = utils.prompt_and_delete(str(repo_dir))
115
116
    assert mock_read_user.called
117
    assert not repo_dir.exists()
118
    assert deleted
119
120
121
def test_prompt_should_ask_and_exit_on_user_no_answer(mocker, tmp_path):
122
    """In `prompt_and_delete()`, if the user decline to delete/reclone the \
123
    repo, cookiecutter should exit."""
124
    mock_read_user = mocker.patch(
125
        'cookiecutter.utils.read_user_yes_no', return_value=False,
126
    )
127
    mock_sys_exit = mocker.patch('sys.exit', return_value=True)
128
    repo_dir = Path(tmp_path, 'repo')
129
    repo_dir.mkdir()
130
131
    deleted = utils.prompt_and_delete(str(repo_dir))
132
133
    assert mock_read_user.called
134
    assert repo_dir.exists()
135
    assert not deleted
136
    assert mock_sys_exit.called
137
138
139
def test_prompt_should_ask_and_rm_repo_file(mocker, tmp_path):
140
    """In `prompt_and_delete()`, if the user agrees to delete/reclone a \
141
    repo file, the repo should be deleted."""
142
    mock_read_user = mocker.patch(
143
        'cookiecutter.utils.read_user_yes_no', return_value=True, autospec=True
144
    )
145
146
    repo_file = tmp_path.joinpath('repo.zip')
147
    repo_file.write_text('this is zipfile content')
148
149
    deleted = utils.prompt_and_delete(str(repo_file))
150
151
    assert mock_read_user.called
152
    assert not repo_file.exists()
153
    assert deleted
154
155
156
def test_prompt_should_ask_and_keep_repo_on_no_reuse(mocker, tmp_path):
157
    """In `prompt_and_delete()`, if the user wants to keep their old \
158
    cloned template repo, it should not be deleted."""
159
    mock_read_user = mocker.patch(
160
        'cookiecutter.utils.read_user_yes_no', return_value=False, autospec=True
161
    )
162
    repo_dir = Path(tmp_path, 'repo')
163
    repo_dir.mkdir()
164
165
    with pytest.raises(SystemExit):
166
        utils.prompt_and_delete(str(repo_dir))
167
168
    assert mock_read_user.called
169
    assert repo_dir.exists()
170
171
172
def test_prompt_should_ask_and_keep_repo_on_reuse(mocker, tmp_path):
173
    """In `prompt_and_delete()`, if the user wants to keep their old \
174
    cloned template repo, it should not be deleted."""
175
176
    def answer(question, default):
177
        if 'okay to delete' in question:
178
            return False
179
        else:
180
            return True
181
182
    mock_read_user = mocker.patch(
183
        'cookiecutter.utils.read_user_yes_no', side_effect=answer, autospec=True
184
    )
185
    repo_dir = Path(tmp_path, 'repo')
186
    repo_dir.mkdir()
187
188
    deleted = utils.prompt_and_delete(str(repo_dir))
189
190
    assert mock_read_user.called
191
    assert repo_dir.exists()
192
    assert not deleted
193
194
195
def test_prompt_should_not_ask_if_no_input_and_rm_repo_dir(mocker, tmp_path):
196
    """Prompt should not ask if no input and rm dir.
197
198
    In `prompt_and_delete()`, if `no_input` is True, the call to
199
    `prompt.read_user_yes_no()` should be suppressed.
200
    """
201
    mock_read_user = mocker.patch(
202
        'cookiecutter.prompt.read_user_yes_no', return_value=True, autospec=True
203
    )
204
    repo_dir = Path(tmp_path, 'repo')
205
    repo_dir.mkdir()
206
207
    deleted = utils.prompt_and_delete(str(repo_dir), no_input=True)
208
209
    assert not mock_read_user.called
210
    assert not repo_dir.exists()
211
    assert deleted
212
213
214
def test_prompt_should_not_ask_if_no_input_and_rm_repo_file(mocker, tmp_path):
215
    """Prompt should not ask if no input and rm file.
216
217
    In `prompt_and_delete()`, if `no_input` is True, the call to
218
    `prompt.read_user_yes_no()` should be suppressed.
219
    """
220
    mock_read_user = mocker.patch(
221
        'cookiecutter.prompt.read_user_yes_no', return_value=True, autospec=True
222
    )
223
224
    repo_file = tmp_path.joinpath('repo.zip')
225
    repo_file.write_text('this is zipfile content')
226
227
    deleted = utils.prompt_and_delete(str(repo_file), no_input=True)
228
229
    assert not mock_read_user.called
230
    assert not repo_file.exists()
231
    assert deleted
232