cookiecutter

Форк
0
/
test_clone.py 
213 строк · 7.0 Кб
1
"""Tests around cloning repositories and detection of errors at it."""
2

3
import os
4
import subprocess
5

6
import pytest
7

8
from cookiecutter import exceptions, vcs
9

10

11
def test_clone_should_raise_if_vcs_not_installed(mocker, clone_dir) -> None:
12
    """In `clone()`, a `VCSNotInstalled` exception should be raised if no VCS \
13
    is installed."""
14
    mocker.patch('cookiecutter.vcs.is_vcs_installed', autospec=True, return_value=False)
15

16
    repo_url = 'https://github.com/pytest-dev/cookiecutter-pytest-plugin.git'
17

18
    with pytest.raises(exceptions.VCSNotInstalled):
19
        vcs.clone(repo_url, clone_to_dir=str(clone_dir))
20

21

22
def test_clone_should_rstrip_trailing_slash_in_repo_url(mocker, clone_dir) -> None:
23
    """In `clone()`, repo URL's trailing slash should be stripped if one is \
24
    present."""
25
    mocker.patch('cookiecutter.vcs.is_vcs_installed', autospec=True, return_value=True)
26

27
    mock_subprocess = mocker.patch(
28
        'cookiecutter.vcs.subprocess.check_output',
29
        autospec=True,
30
    )
31

32
    vcs.clone('https://github.com/foo/bar/', clone_to_dir=clone_dir, no_input=True)
33

34
    mock_subprocess.assert_called_once_with(
35
        ['git', 'clone', 'https://github.com/foo/bar'],
36
        cwd=clone_dir,
37
        stderr=subprocess.STDOUT,
38
    )
39

40

41
def test_clone_should_abort_if_user_does_not_want_to_reclone(mocker, clone_dir) -> None:
42
    """In `clone()`, if user doesn't want to reclone, Cookiecutter should exit \
43
    without cloning anything."""
44
    mocker.patch('cookiecutter.vcs.is_vcs_installed', autospec=True, return_value=True)
45
    mocker.patch(
46
        'cookiecutter.vcs.prompt_and_delete', side_effect=SystemExit, autospec=True
47
    )
48
    mock_subprocess = mocker.patch(
49
        'cookiecutter.vcs.subprocess.check_output',
50
        autospec=True,
51
    )
52

53
    # Create repo_dir to trigger prompt_and_delete
54
    repo_dir = clone_dir.joinpath('cookiecutter-pytest-plugin')
55
    repo_dir.mkdir()
56

57
    repo_url = 'https://github.com/pytest-dev/cookiecutter-pytest-plugin.git'
58

59
    with pytest.raises(SystemExit):
60
        vcs.clone(repo_url, clone_to_dir=str(clone_dir))
61
    assert not mock_subprocess.called
62

63

64
def test_clone_should_silent_exit_if_ok_to_reuse(mocker, tmpdir) -> None:
65
    """In `clone()`, if user doesn't want to reclone, Cookiecutter should exit \
66
    without cloning anything."""
67
    mocker.patch('cookiecutter.vcs.is_vcs_installed', autospec=True, return_value=True)
68
    mocker.patch(
69
        'cookiecutter.vcs.prompt_and_delete', return_value=False, autospec=True
70
    )
71
    mock_subprocess = mocker.patch(
72
        'cookiecutter.vcs.subprocess.check_output',
73
        autospec=True,
74
    )
75

76
    clone_to_dir = tmpdir.mkdir('clone')
77

78
    # Create repo_dir to trigger prompt_and_delete
79
    clone_to_dir.mkdir('cookiecutter-pytest-plugin')
80

81
    repo_url = 'https://github.com/pytest-dev/cookiecutter-pytest-plugin.git'
82

83
    vcs.clone(repo_url, clone_to_dir=str(clone_to_dir))
84
    assert not mock_subprocess.called
85

86

87
@pytest.mark.parametrize(
88
    'repo_type, repo_url, repo_name',
89
    [
90
        ('git', 'https://github.com/hello/world.git', 'world'),
91
        ('hg', 'https://bitbucket.org/foo/bar', 'bar'),
92
        ('git', 'git@host:gitoliterepo', 'gitoliterepo'),
93
        ('git', 'git@gitlab.com:cookiecutter/cookiecutter.git', 'cookiecutter'),
94
        ('git', 'git@github.com:cookiecutter/cookiecutter.git', 'cookiecutter'),
95
    ],
96
)
97
def test_clone_should_invoke_vcs_command(
98
    mocker, clone_dir, repo_type, repo_url, repo_name
99
) -> None:
100
    """When `clone()` is called with a git/hg repo, the corresponding VCS \
101
    command should be run via `subprocess.check_output()`.
102

103
    This should take place:
104
    * In the correct dir
105
    * With the correct args.
106
    """
107
    mocker.patch('cookiecutter.vcs.is_vcs_installed', autospec=True, return_value=True)
108

109
    mock_subprocess = mocker.patch(
110
        'cookiecutter.vcs.subprocess.check_output',
111
        autospec=True,
112
    )
113
    expected_repo_dir = os.path.normpath(os.path.join(clone_dir, repo_name))
114

115
    branch = 'foobar'
116

117
    repo_dir = vcs.clone(
118
        repo_url, checkout=branch, clone_to_dir=clone_dir, no_input=True
119
    )
120

121
    assert repo_dir == expected_repo_dir
122

123
    mock_subprocess.assert_any_call(
124
        [repo_type, 'clone', repo_url], cwd=clone_dir, stderr=subprocess.STDOUT
125
    )
126

127
    branch_info = [branch]
128
    # We sanitize branch information for Mercurial
129
    if repo_type == "hg":
130
        branch_info.insert(0, "--")
131

132
    mock_subprocess.assert_any_call(
133
        [repo_type, 'checkout', *branch_info],
134
        cwd=expected_repo_dir,
135
        stderr=subprocess.STDOUT,
136
    )
137

138

139
@pytest.mark.parametrize(
140
    'error_message',
141
    [
142
        (b"fatal: repository 'https://github.com/hackebro/cookiedozer' not found"),
143
        b'hg: abort: HTTP Error 404: Not Found',
144
    ],
145
)
146
def test_clone_handles_repo_typo(mocker, clone_dir, error_message) -> None:
147
    """In `clone()`, repository not found errors should raise an \
148
    appropriate exception."""
149
    # side_effect is set to an iterable here (and below),
150
    # because of a Python 3.4 unittest.mock regression
151
    # http://bugs.python.org/issue23661
152
    mocker.patch(
153
        'cookiecutter.vcs.subprocess.check_output',
154
        autospec=True,
155
        side_effect=[subprocess.CalledProcessError(-1, 'cmd', output=error_message)],
156
    )
157

158
    repository_url = 'https://github.com/hackebro/cookiedozer'
159
    with pytest.raises(exceptions.RepositoryNotFound) as err:
160
        vcs.clone(repository_url, clone_to_dir=str(clone_dir), no_input=True)
161

162
    assert str(err.value) == (
163
        f'The repository {repository_url} could not be found, have you made a typo?'
164
    )
165

166

167
@pytest.mark.parametrize(
168
    'error_message',
169
    [
170
        b"error: pathspec 'unknown_branch' did not match any file(s) known to git",
171
        b"hg: abort: unknown revision 'unknown_branch'!",
172
    ],
173
)
174
def test_clone_handles_branch_typo(mocker, clone_dir, error_message) -> None:
175
    """In `clone()`, branch not found errors should raise an \
176
    appropriate exception."""
177
    mocker.patch(
178
        'cookiecutter.vcs.subprocess.check_output',
179
        autospec=True,
180
        side_effect=[subprocess.CalledProcessError(-1, 'cmd', output=error_message)],
181
    )
182

183
    repository_url = 'https://github.com/pytest-dev/cookiecutter-pytest-plugin'
184
    with pytest.raises(exceptions.RepositoryCloneFailed) as err:
185
        vcs.clone(
186
            repository_url,
187
            clone_to_dir=str(clone_dir),
188
            checkout='unknown_branch',
189
            no_input=True,
190
        )
191

192
    assert str(err.value) == (
193
        'The unknown_branch branch of repository '
194
        f'{repository_url} could not found, have you made a typo?'
195
    )
196

197

198
def test_clone_unknown_subprocess_error(mocker, clone_dir) -> None:
199
    """In `clone()`, unknown subprocess errors should be raised."""
200
    mocker.patch(
201
        'cookiecutter.vcs.subprocess.check_output',
202
        autospec=True,
203
        side_effect=[
204
            subprocess.CalledProcessError(-1, 'cmd', output=b'Something went wrong')
205
        ],
206
    )
207

208
    with pytest.raises(subprocess.CalledProcessError):
209
        vcs.clone(
210
            'https://github.com/pytest-dev/cookiecutter-pytest-plugin',
211
            clone_to_dir=str(clone_dir),
212
            no_input=True,
213
        )
214

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

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

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

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