|
1
|
|
|
# -*- coding: utf-8 -*- |
|
2
|
|
|
import os |
|
3
|
|
|
|
|
4
|
|
|
import pytest |
|
5
|
|
|
|
|
6
|
|
|
from cookiecutter import config |
|
7
|
|
|
from cookiecutter.exceptions import (InvalidConfiguration, |
|
8
|
|
|
ConfigDoesNotExistException) |
|
9
|
|
|
|
|
10
|
|
|
|
|
11
|
|
|
def test_find_user_config_envvar_is_valid_path(monkeypatch, tmpdir): |
|
12
|
|
|
"""If COOKIECUTTER_CONFIG is set and valid, use it""" |
|
13
|
|
|
# .ensure makes the path exist so it passes os.path.isfile |
|
14
|
|
|
path = tmpdir.mkdir('spoofdir').join('spoofrc').ensure() |
|
15
|
|
|
monkeypatch.setenv('COOKIECUTTER_CONFIG', str(path)) |
|
16
|
|
|
assert config._find_user_config() == str(path) |
|
17
|
|
|
|
|
18
|
|
|
|
|
19
|
|
|
def test_find_user_config_raises_for_invalid_envvar(monkeypatch, tmpdir): |
|
20
|
|
|
"""If COOKIECUTTER_CONFIG is set but not a file, |
|
21
|
|
|
raise ConfigDoesNotExistException |
|
22
|
|
|
""" |
|
23
|
|
|
# path doesn't actually exist unless we call ensure |
|
24
|
|
|
path = tmpdir.mkdir('spoofdir').join('spoofrc') |
|
25
|
|
|
monkeypatch.setenv('COOKIECUTTER_CONFIG', str(path)) |
|
26
|
|
|
with pytest.raises(ConfigDoesNotExistException): |
|
27
|
|
|
config._find_user_config() |
|
28
|
|
|
|
|
29
|
|
|
|
|
30
|
|
|
def test_find_user_config_gets_existing_default(monkeypatch, tmpdir): |
|
31
|
|
|
""" |
|
32
|
|
|
If COOKIECUTTER_CONFIG is unset but ~/.cookiecutterrc exists, return it |
|
33
|
|
|
""" |
|
34
|
|
|
base_path = tmpdir.mkdir('spoofdir') |
|
35
|
|
|
# we can't just patch cookiecutter.config.expanduser; the value of |
|
36
|
|
|
# USER_CONFIG_FALLBACK_PATH is set at import time, which is prior to when |
|
37
|
|
|
# we can patch - so patch the computed constant directly against the |
|
38
|
|
|
# imported module |
|
39
|
|
|
monkeypatch.setattr(config, |
|
40
|
|
|
'USER_CONFIG_FALLBACK_PATH', |
|
41
|
|
|
str(base_path.join('.cookiecutterrc'))) |
|
42
|
|
|
default_conf_path = str(base_path.join('.cookiecutterrc').ensure()) |
|
43
|
|
|
monkeypatch.delenv('COOKIECUTTER_CONFIG', raising=False) |
|
44
|
|
|
assert config._find_user_config() == default_conf_path |
|
45
|
|
|
|
|
46
|
|
|
|
|
47
|
|
|
@pytest.mark.parametrize("platform", ['XDG', 'NIX', 'OSX', 'WIN', None]) |
|
48
|
|
|
def test_find_user_config_platform_dir_search_path(monkeypatch, |
|
49
|
|
|
tmpdir, |
|
50
|
|
|
platform): |
|
51
|
|
|
r""" |
|
52
|
|
|
If COOKIECUTTER_CONFIG is unset and ~/.cookiecutterrc does not exist, then |
|
53
|
|
|
search the following: |
|
54
|
|
|
$XDG_CONFIG_HOME/cookiecutter/config |
|
55
|
|
|
%APPDATA%\cookiecutter\config |
|
56
|
|
|
~/.config/cookiecutter/config |
|
57
|
|
|
~/Library/Application\ Support/cookiecutter/config |
|
58
|
|
|
And the return the first match that exists |
|
59
|
|
|
""" |
|
60
|
|
|
base_path = tmpdir.mkdir('spoofdir') |
|
61
|
|
|
# patch this in this test so we can assert it isn't a file (since nothing |
|
62
|
|
|
# below is supposed to run if it is) |
|
63
|
|
|
monkeypatch.setattr(config, |
|
64
|
|
|
'USER_CONFIG_FALLBACK_PATH', |
|
65
|
|
|
str(base_path.join('.cookiecutterrc'))) |
|
66
|
|
|
# preconditions of searching for a platform-specific dir |
|
67
|
|
|
monkeypatch.delenv('COOKIECUTTER_CONFIG', raising=False) |
|
68
|
|
|
assert not os.path.isfile(config.USER_CONFIG_FALLBACK_PATH) |
|
69
|
|
|
|
|
70
|
|
|
search_path = { |
|
71
|
|
|
# make them unique - they're just envvars, so they could be anything |
|
72
|
|
|
'XDG': base_path.join('XDG'), |
|
73
|
|
|
'WIN': base_path.join('WIN'), |
|
74
|
|
|
# these two are a little more concrete - they have to match what's |
|
75
|
|
|
# hardcoded in the join in cookiecutter/config.py |
|
76
|
|
|
'NIX': base_path.join('.config'), |
|
77
|
|
|
'OSX': base_path.join('Library', 'Application Support') |
|
78
|
|
|
} |
|
79
|
|
|
monkeypatch.setenv('XDG_CONFIG_HOME', str(search_path['XDG'])) |
|
80
|
|
|
monkeypatch.setenv('APPDATA', str(search_path['WIN'])) |
|
81
|
|
|
monkeypatch.setattr(config, 'HOME_DIR', str(base_path)) |
|
82
|
|
|
|
|
83
|
|
|
if platform is None: |
|
84
|
|
|
assert config._find_user_config() is None |
|
85
|
|
|
return |
|
86
|
|
|
|
|
87
|
|
|
path = search_path.pop(platform) |
|
88
|
|
|
path = path.join('cookiecutter', 'config').ensure() |
|
89
|
|
|
|
|
90
|
|
|
assert config._find_user_config() == str(path) |
|
91
|
|
|
for _, other_path in search_path.items(): |
|
92
|
|
|
assert config._find_user_config() != str(other_path) |
|
93
|
|
|
|
|
94
|
|
|
|
|
95
|
|
|
@pytest.mark.parametrize('kind', ['cookiecutters_dir', 'cookiecutter_replay']) |
|
96
|
|
|
def test_find_user_data_dir_valid_envvar(monkeypatch, tmpdir, kind): |
|
97
|
|
|
tmpdatadir = tmpdir.mkdir('spoof').join('temprc').ensure(dir=True) |
|
98
|
|
|
monkeypatch.setenv(kind.upper(), str(tmpdatadir)) |
|
99
|
|
|
assert config._find_user_data_dir(kind) == str(tmpdatadir) |
|
100
|
|
|
|
|
101
|
|
|
|
|
102
|
|
|
@pytest.mark.parametrize('kind', ['cookiecutters_dir', 'cookiecutter_replay']) |
|
103
|
|
|
def test_find_user_data_dir_preexisting_dotdir(monkeypatch, tmpdir, kind): |
|
104
|
|
|
tmphome = tmpdir.mkdir('phonyhome') |
|
105
|
|
|
monkeypatch.setattr(config, 'HOME_DIR', str(tmphome)) |
|
106
|
|
|
tmpdatadir = tmphome.join('.{}'.format(kind.lower())).ensure(dir=True) |
|
107
|
|
|
assert config._find_user_data_dir(kind) == str(tmpdatadir) |
|
108
|
|
|
|
|
109
|
|
|
|
|
110
|
|
|
@pytest.mark.parametrize('kind', ['cookiecutters_dir', 'cookiecutter_replay']) |
|
111
|
|
|
def test_find_user_data_dir_falls_back_to_user_home(monkeypatch, tmpdir, kind): |
|
112
|
|
|
monkeypatch.delenv(kind.upper(), raising=False) |
|
113
|
|
|
monkeypatch.delenv('XDG_DATA_HOME', raising=False) |
|
114
|
|
|
monkeypatch.delenv('APPDATA', raising=False) |
|
115
|
|
|
mockdir = tmpdir.mkdir('mock') |
|
116
|
|
|
monkeypatch.setattr(config, 'HOME_DIR', str(mockdir)) |
|
117
|
|
|
expected = os.path.normpath('{}/.{}'.format(str(mockdir), kind.lower())) |
|
118
|
|
|
assert config._find_user_data_dir(kind) == expected |
|
119
|
|
|
|
|
120
|
|
|
|
|
121
|
|
|
def test_merge_configs(): |
|
122
|
|
|
default = { |
|
123
|
|
|
'cookiecutters_dir': '/home/example/some-path-to-templates', |
|
124
|
|
|
'replay_dir': '/home/example/some-path-to-replay-files', |
|
125
|
|
|
'default_context': {}, |
|
126
|
|
|
'abbreviations': { |
|
127
|
|
|
'gh': 'https://github.com/{0}.git', |
|
128
|
|
|
'gl': 'https://gitlab.com/{0}.git', |
|
129
|
|
|
'bb': 'https://bitbucket.org/{0}', |
|
130
|
|
|
} |
|
131
|
|
|
} |
|
132
|
|
|
|
|
133
|
|
|
user_config = { |
|
134
|
|
|
'default_context': { |
|
135
|
|
|
'full_name': 'Raphael Pierzina', |
|
136
|
|
|
'github_username': 'hackebrot', |
|
137
|
|
|
}, |
|
138
|
|
|
'abbreviations': { |
|
139
|
|
|
'gl': 'https://gitlab.com/hackebrot/{0}.git', |
|
140
|
|
|
'pytest-plugin': 'https://github.com/pytest-dev/pytest-plugin.git', |
|
141
|
|
|
} |
|
142
|
|
|
} |
|
143
|
|
|
|
|
144
|
|
|
expected_config = { |
|
145
|
|
|
'cookiecutters_dir': '/home/example/some-path-to-templates', |
|
146
|
|
|
'replay_dir': '/home/example/some-path-to-replay-files', |
|
147
|
|
|
'default_context': { |
|
148
|
|
|
'full_name': 'Raphael Pierzina', |
|
149
|
|
|
'github_username': 'hackebrot', |
|
150
|
|
|
}, |
|
151
|
|
|
'abbreviations': { |
|
152
|
|
|
'gh': 'https://github.com/{0}.git', |
|
153
|
|
|
'gl': 'https://gitlab.com/hackebrot/{0}.git', |
|
154
|
|
|
'bb': 'https://bitbucket.org/{0}', |
|
155
|
|
|
'pytest-plugin': 'https://github.com/pytest-dev/pytest-plugin.git', |
|
156
|
|
|
} |
|
157
|
|
|
} |
|
158
|
|
|
|
|
159
|
|
|
assert config.merge_configs(default, user_config) == expected_config |
|
160
|
|
|
|
|
161
|
|
|
|
|
162
|
|
|
def test_get_config(): |
|
163
|
|
|
""" |
|
164
|
|
|
Opening and reading config file |
|
165
|
|
|
""" |
|
166
|
|
|
conf = config.get_config('tests/test-config/valid-config.yaml') |
|
167
|
|
|
expected_conf = { |
|
168
|
|
|
'cookiecutters_dir': '/home/example/some-path-to-templates', |
|
169
|
|
|
'replay_dir': '/home/example/some-path-to-replay-files', |
|
170
|
|
|
'default_context': { |
|
171
|
|
|
'full_name': 'Firstname Lastname', |
|
172
|
|
|
'email': '[email protected]', |
|
173
|
|
|
'github_username': 'example' |
|
174
|
|
|
}, |
|
175
|
|
|
'abbreviations': { |
|
176
|
|
|
'gh': 'https://github.com/{0}.git', |
|
177
|
|
|
'gl': 'https://gitlab.com/{0}.git', |
|
178
|
|
|
'bb': 'https://bitbucket.org/{0}', |
|
179
|
|
|
'helloworld': 'https://github.com/hackebrot/helloworld' |
|
180
|
|
|
} |
|
181
|
|
|
} |
|
182
|
|
|
assert conf == expected_conf |
|
183
|
|
|
|
|
184
|
|
|
|
|
185
|
|
|
def test_get_config_does_not_exist(): |
|
186
|
|
|
""" |
|
187
|
|
|
Check that `exceptions.ConfigDoesNotExistException` is raised when |
|
188
|
|
|
attempting to get a non-existent config file. |
|
189
|
|
|
""" |
|
190
|
|
|
with pytest.raises(ConfigDoesNotExistException): |
|
191
|
|
|
config.get_config('tests/test-config/this-does-not-exist.yaml') |
|
192
|
|
|
|
|
193
|
|
|
|
|
194
|
|
|
def test_invalid_config(): |
|
195
|
|
|
""" |
|
196
|
|
|
An invalid config file should raise an `InvalidConfiguration` exception. |
|
197
|
|
|
""" |
|
198
|
|
|
with pytest.raises(InvalidConfiguration) as excinfo: |
|
199
|
|
|
config.get_config('tests/test-config/invalid-config.yaml') |
|
200
|
|
|
|
|
201
|
|
|
expected_error_msg = ( |
|
202
|
|
|
'Unable to parse YAML file ' |
|
203
|
|
|
'tests/test-config/invalid-config.yaml. ' |
|
204
|
|
|
'Error: ' |
|
205
|
|
|
) |
|
206
|
|
|
assert expected_error_msg in str(excinfo.value) |
|
207
|
|
|
|
|
208
|
|
|
|
|
209
|
|
|
def test_get_config_with_defaults(): |
|
210
|
|
|
""" |
|
211
|
|
|
A config file that overrides 1 of 3 defaults |
|
212
|
|
|
""" |
|
213
|
|
|
conf = config.get_config('tests/test-config/valid-partial-config.yaml') |
|
214
|
|
|
# use the defaults directly rather than invoke config._find_user_data_dir; |
|
215
|
|
|
# _find_user_data_dir should be an implementation detail |
|
216
|
|
|
default_cookiecutters_dir = config.DEFAULT_CONFIG['cookiecutters_dir'] |
|
217
|
|
|
default_replay_dir = config.DEFAULT_CONFIG['replay_dir'] |
|
218
|
|
|
expected_conf = { |
|
219
|
|
|
'cookiecutters_dir': default_cookiecutters_dir, |
|
220
|
|
|
'replay_dir': default_replay_dir, |
|
221
|
|
|
'default_context': { |
|
222
|
|
|
'full_name': 'Firstname Lastname', |
|
223
|
|
|
'email': '[email protected]', |
|
224
|
|
|
'github_username': 'example' |
|
225
|
|
|
}, |
|
226
|
|
|
'abbreviations': { |
|
227
|
|
|
'gh': 'https://github.com/{0}.git', |
|
228
|
|
|
'gl': 'https://gitlab.com/{0}.git', |
|
229
|
|
|
'bb': 'https://bitbucket.org/{0}', |
|
230
|
|
|
} |
|
231
|
|
|
} |
|
232
|
|
|
assert conf == expected_conf |
|
233
|
|
|
|