1 | """Tests for `generate_files` function and related errors raising. |
||
2 | |||
3 | Use the global clean_system fixture and run additional teardown code to remove |
||
4 | some special folders. |
||
5 | """ |
||
6 | from pathlib import Path |
||
7 | |||
8 | import pytest |
||
9 | from binaryornot.check import is_binary |
||
10 | |||
11 | from cookiecutter import exceptions, generate |
||
12 | |||
13 | |||
14 | @pytest.mark.parametrize('invalid_dirname', ['', '{foo}', '{{foo', 'bar}}']) |
||
15 | def test_ensure_dir_is_templated_raises(invalid_dirname): |
||
16 | """Verify `ensure_dir_is_templated` raises on wrong directories names input.""" |
||
17 | with pytest.raises(exceptions.NonTemplatedInputDirException): |
||
18 | generate.ensure_dir_is_templated(invalid_dirname) |
||
19 | |||
20 | |||
21 | def test_generate_files_nontemplated_exception(tmp_path): |
||
22 | """ |
||
23 | Verify `generate_files` raises when no directories to render exist. |
||
24 | |||
25 | Note: Check `tests/test-generate-files-nontemplated` location to understand. |
||
26 | """ |
||
27 | with pytest.raises(exceptions.NonTemplatedInputDirException): |
||
28 | generate.generate_files( |
||
29 | context={'cookiecutter': {'food': 'pizza'}}, |
||
30 | repo_dir='tests/test-generate-files-nontemplated', |
||
31 | output_dir=tmp_path, |
||
32 | ) |
||
33 | |||
34 | |||
35 | def test_generate_files(tmp_path): |
||
36 | """Verify directory name correctly rendered with unicode containing context.""" |
||
37 | generate.generate_files( |
||
38 | context={'cookiecutter': {'food': 'pizzä'}}, |
||
39 | repo_dir='tests/test-generate-files', |
||
40 | output_dir=tmp_path, |
||
41 | ) |
||
42 | |||
43 | simple_file = Path(tmp_path, 'inputpizzä/simple.txt') |
||
44 | assert simple_file.exists() |
||
45 | assert simple_file.is_file() |
||
46 | |||
47 | simple_text = Path(simple_file).read_text(encoding='utf-8') |
||
48 | assert simple_text == 'I eat pizzä' |
||
49 | |||
50 | |||
51 | View Code Duplication | def test_generate_files_with_linux_newline(tmp_path): |
|
0 ignored issues
–
show
Duplication
introduced
by
Loading history...
|
|||
52 | """Verify new line not removed by templating engine after folder generation.""" |
||
53 | generate.generate_files( |
||
54 | context={'cookiecutter': {'food': 'pizzä'}}, |
||
55 | repo_dir='tests/test-generate-files', |
||
56 | output_dir=tmp_path, |
||
57 | ) |
||
58 | |||
59 | newline_file = Path(tmp_path, 'inputpizzä/simple-with-newline.txt') |
||
60 | assert newline_file.is_file() |
||
61 | assert newline_file.exists() |
||
62 | |||
63 | with Path(newline_file).open(encoding='utf-8', newline='') as f: |
||
64 | simple_text = f.readline() |
||
65 | assert simple_text == 'newline is LF\n' |
||
66 | assert f.newlines == '\n' |
||
67 | |||
68 | |||
69 | def test_generate_files_with_jinja2_environment(tmp_path): |
||
70 | """Extend StrictEnvironment with _jinja2_env_vars cookiecutter template option.""" |
||
71 | generate.generate_files( |
||
72 | context={ |
||
73 | 'cookiecutter': { |
||
74 | 'food': 'pizzä', |
||
75 | '_jinja2_env_vars': {'lstrip_blocks': True, 'trim_blocks': True}, |
||
76 | } |
||
77 | }, |
||
78 | repo_dir='tests/test-generate-files', |
||
79 | output_dir=tmp_path, |
||
80 | ) |
||
81 | |||
82 | conditions_file = tmp_path.joinpath('inputpizzä/simple-with-conditions.txt') |
||
83 | assert conditions_file.is_file() |
||
84 | assert conditions_file.exists() |
||
85 | |||
86 | simple_text = conditions_file.read_text(encoding='utf-8') |
||
87 | assert simple_text == 'I eat pizzä\n' |
||
88 | |||
89 | |||
90 | View Code Duplication | def test_generate_files_with_trailing_newline_forced_to_linux_by_context(tmp_path): |
|
0 ignored issues
–
show
|
|||
91 | """Verify new line not removed by templating engine after folder generation.""" |
||
92 | generate.generate_files( |
||
93 | context={'cookiecutter': {'food': 'pizzä', '_new_lines': '\r\n'}}, |
||
94 | repo_dir='tests/test-generate-files', |
||
95 | output_dir=tmp_path, |
||
96 | ) |
||
97 | |||
98 | # assert 'Overwritting endline character with %s' in caplog.messages |
||
99 | newline_file = Path(tmp_path, 'inputpizzä/simple-with-newline.txt') |
||
100 | assert newline_file.is_file() |
||
101 | assert newline_file.exists() |
||
102 | |||
103 | with Path(newline_file).open(encoding='utf-8', newline='') as f: |
||
104 | simple_text = f.readline() |
||
105 | assert simple_text == 'newline is LF\r\n' |
||
106 | assert f.newlines == '\r\n' |
||
107 | |||
108 | |||
109 | View Code Duplication | def test_generate_files_with_windows_newline(tmp_path): |
|
0 ignored issues
–
show
|
|||
110 | """Verify windows source line end not changed during files generation.""" |
||
111 | generate.generate_files( |
||
112 | context={'cookiecutter': {'food': 'pizzä'}}, |
||
113 | repo_dir='tests/test-generate-files', |
||
114 | output_dir=tmp_path, |
||
115 | ) |
||
116 | |||
117 | newline_file = Path(tmp_path, 'inputpizzä/simple-with-newline-crlf.txt') |
||
118 | assert newline_file.is_file() |
||
119 | assert newline_file.exists() |
||
120 | |||
121 | with Path(newline_file).open(encoding='utf-8', newline='') as f: |
||
122 | simple_text = f.readline() |
||
123 | assert simple_text == 'newline is CRLF\r\n' |
||
124 | assert f.newlines == '\r\n' |
||
125 | |||
126 | |||
127 | View Code Duplication | def test_generate_files_with_windows_newline_forced_to_linux_by_context(tmp_path): |
|
0 ignored issues
–
show
|
|||
128 | """Verify windows line end changed to linux during files generation.""" |
||
129 | generate.generate_files( |
||
130 | context={'cookiecutter': {'food': 'pizzä', '_new_lines': '\n'}}, |
||
131 | repo_dir='tests/test-generate-files', |
||
132 | output_dir=tmp_path, |
||
133 | ) |
||
134 | |||
135 | newline_file = Path(tmp_path, 'inputpizzä/simple-with-newline-crlf.txt') |
||
136 | assert newline_file.is_file() |
||
137 | assert newline_file.exists() |
||
138 | |||
139 | with Path(newline_file).open(encoding='utf-8', newline='') as f: |
||
140 | simple_text = f.readline() |
||
141 | |||
142 | assert simple_text == 'newline is CRLF\n' |
||
143 | assert f.newlines == '\n' |
||
144 | |||
145 | |||
146 | def test_generate_files_binaries(tmp_path): |
||
147 | """Verify binary files created during directory generation.""" |
||
148 | generate.generate_files( |
||
149 | context={'cookiecutter': {'binary_test': 'binary_files'}}, |
||
150 | repo_dir='tests/test-generate-binaries', |
||
151 | output_dir=tmp_path, |
||
152 | ) |
||
153 | |||
154 | dst_dir = Path(tmp_path, 'inputbinary_files') |
||
155 | |||
156 | assert is_binary(str(Path(dst_dir, 'logo.png'))) |
||
157 | assert is_binary(str(Path(dst_dir, '.DS_Store'))) |
||
158 | assert not is_binary(str(Path(dst_dir, 'readme.txt'))) |
||
159 | assert is_binary(str(Path(dst_dir, 'some_font.otf'))) |
||
160 | assert is_binary(str(Path(dst_dir, 'binary_files/logo.png'))) |
||
161 | assert is_binary(str(Path(dst_dir, 'binary_files/.DS_Store'))) |
||
162 | assert not is_binary(str(Path(dst_dir, 'binary_files/readme.txt'))) |
||
163 | assert is_binary(str(Path(dst_dir, 'binary_files/some_font.otf'))) |
||
164 | assert is_binary(str(Path(dst_dir, 'binary_files/binary_files/logo.png'))) |
||
165 | |||
166 | |||
167 | def test_generate_files_absolute_path(tmp_path): |
||
168 | """Verify usage of absolute path does not change files generation behaviour.""" |
||
169 | generate.generate_files( |
||
170 | context={'cookiecutter': {'food': 'pizzä'}}, |
||
171 | repo_dir=Path('tests/test-generate-files').absolute(), |
||
172 | output_dir=tmp_path, |
||
173 | ) |
||
174 | assert Path(tmp_path, 'inputpizzä/simple.txt').is_file() |
||
175 | |||
176 | |||
177 | def test_generate_files_output_dir(tmp_path): |
||
178 | """Verify `output_dir` option for `generate_files` changing location correctly.""" |
||
179 | output_dir = Path(tmp_path, 'custom_output_dir') |
||
180 | output_dir.mkdir() |
||
181 | |||
182 | project_dir = generate.generate_files( |
||
183 | context={'cookiecutter': {'food': 'pizzä'}}, |
||
184 | repo_dir=Path('tests/test-generate-files').absolute(), |
||
185 | output_dir=output_dir, |
||
186 | ) |
||
187 | |||
188 | assert Path(output_dir, 'inputpizzä/simple.txt').exists() |
||
189 | assert Path(output_dir, 'inputpizzä/simple.txt').is_file() |
||
190 | assert Path(project_dir) == Path(tmp_path, 'custom_output_dir/inputpizzä') |
||
191 | |||
192 | |||
193 | def test_generate_files_permissions(tmp_path): |
||
194 | """Verify generates files respect source files permissions. |
||
195 | |||
196 | simple.txt and script.sh should retain their respective 0o644 and 0o755 |
||
197 | permissions. |
||
198 | """ |
||
199 | generate.generate_files( |
||
200 | context={'cookiecutter': {'permissions': 'permissions'}}, |
||
201 | repo_dir='tests/test-generate-files-permissions', |
||
202 | output_dir=tmp_path, |
||
203 | ) |
||
204 | |||
205 | assert Path(tmp_path, 'inputpermissions/simple.txt').is_file() |
||
206 | |||
207 | # Verify source simple.txt should still be 0o644 |
||
208 | tests_simple_file = Path( |
||
209 | 'tests', |
||
210 | 'test-generate-files-permissions', |
||
211 | 'input{{cookiecutter.permissions}}', |
||
212 | 'simple.txt', |
||
213 | ) |
||
214 | tests_simple_file_mode = tests_simple_file.stat().st_mode |
||
215 | |||
216 | input_simple_file = Path(tmp_path, 'inputpermissions', 'simple.txt') |
||
217 | input_simple_file_mode = input_simple_file.stat().st_mode |
||
218 | assert tests_simple_file_mode == input_simple_file_mode |
||
219 | |||
220 | assert Path(tmp_path, 'inputpermissions/script.sh').exists() |
||
221 | assert Path(tmp_path, 'inputpermissions/script.sh').is_file() |
||
222 | |||
223 | # Verify source script.sh should still be 0o755 |
||
224 | tests_script_file = Path( |
||
225 | 'tests', |
||
226 | 'test-generate-files-permissions', |
||
227 | 'input{{cookiecutter.permissions}}', |
||
228 | 'script.sh', |
||
229 | ) |
||
230 | tests_script_file_mode = tests_script_file.stat().st_mode |
||
231 | |||
232 | input_script_file = Path(tmp_path, 'inputpermissions', 'script.sh') |
||
233 | input_script_file_mode = input_script_file.stat().st_mode |
||
234 | assert tests_script_file_mode == input_script_file_mode |
||
235 | |||
236 | |||
237 | View Code Duplication | def test_generate_files_with_overwrite_if_exists_with_skip_if_file_exists(tmp_path): |
|
0 ignored issues
–
show
|
|||
238 | """Verify `skip_if_file_exist` has priority over `overwrite_if_exists`.""" |
||
239 | simple_file = Path(tmp_path, 'inputpizzä/simple.txt') |
||
240 | simple_with_new_line_file = Path(tmp_path, 'inputpizzä/simple-with-newline.txt') |
||
241 | |||
242 | Path(tmp_path, 'inputpizzä').mkdir(parents=True) |
||
243 | with Path(simple_file).open('w') as f: |
||
244 | f.write('temp') |
||
245 | |||
246 | generate.generate_files( |
||
247 | context={'cookiecutter': {'food': 'pizzä'}}, |
||
248 | repo_dir='tests/test-generate-files', |
||
249 | overwrite_if_exists=True, |
||
250 | skip_if_file_exists=True, |
||
251 | output_dir=tmp_path, |
||
252 | ) |
||
253 | |||
254 | assert Path(simple_file).is_file() |
||
255 | assert Path(simple_file).exists() |
||
256 | assert Path(simple_with_new_line_file).is_file() |
||
257 | assert Path(simple_with_new_line_file).exists() |
||
258 | |||
259 | simple_text = Path(simple_file).read_text(encoding='utf-8') |
||
260 | assert simple_text == 'temp' |
||
261 | |||
262 | |||
263 | View Code Duplication | def test_generate_files_with_skip_if_file_exists(tmp_path): |
|
0 ignored issues
–
show
|
|||
264 | """Verify existed files not removed if error raised with `skip_if_file_exists`.""" |
||
265 | simple_file = Path(tmp_path, 'inputpizzä/simple.txt') |
||
266 | simple_with_new_line_file = Path(tmp_path, 'inputpizzä/simple-with-newline.txt') |
||
267 | |||
268 | Path(tmp_path, 'inputpizzä').mkdir(parents=True) |
||
269 | Path(simple_file).write_text('temp') |
||
270 | |||
271 | with pytest.raises(exceptions.OutputDirExistsException): |
||
272 | generate.generate_files( |
||
273 | context={'cookiecutter': {'food': 'pizzä'}}, |
||
274 | repo_dir='tests/test-generate-files', |
||
275 | skip_if_file_exists=True, |
||
276 | output_dir=tmp_path, |
||
277 | ) |
||
278 | |||
279 | assert Path(simple_file).is_file() |
||
280 | assert not Path(simple_with_new_line_file).is_file() |
||
281 | assert not Path(simple_with_new_line_file).exists() |
||
282 | |||
283 | simple_text = Path(simple_file).read_text(encoding='utf-8') |
||
284 | assert simple_text == 'temp' |
||
285 | |||
286 | |||
287 | View Code Duplication | def test_generate_files_with_overwrite_if_exists(tmp_path): |
|
0 ignored issues
–
show
|
|||
288 | """Verify overwrite_if_exists overwrites old files.""" |
||
289 | simple_file = Path(tmp_path, 'inputpizzä/simple.txt') |
||
290 | simple_with_new_line_file = Path(tmp_path, 'inputpizzä/simple-with-newline.txt') |
||
291 | |||
292 | Path(tmp_path, 'inputpizzä').mkdir(parents=True) |
||
293 | Path(simple_file).write_text('temp') |
||
294 | |||
295 | generate.generate_files( |
||
296 | context={'cookiecutter': {'food': 'pizzä'}}, |
||
297 | repo_dir='tests/test-generate-files', |
||
298 | overwrite_if_exists=True, |
||
299 | output_dir=tmp_path, |
||
300 | ) |
||
301 | |||
302 | assert Path(simple_file).is_file() |
||
303 | assert Path(simple_file).exists() |
||
304 | assert Path(simple_with_new_line_file).is_file() |
||
305 | assert Path(simple_with_new_line_file).exists() |
||
306 | |||
307 | simple_text = Path(simple_file).read_text(encoding='utf-8') |
||
308 | assert simple_text == 'I eat pizzä' |
||
309 | |||
310 | |||
311 | @pytest.fixture |
||
312 | def undefined_context(): |
||
313 | """Fixture. Populate context variable for future tests.""" |
||
314 | return { |
||
315 | 'cookiecutter': {'project_slug': 'testproject', 'github_username': 'hackebrot'} |
||
316 | } |
||
317 | |||
318 | |||
319 | def test_raise_undefined_variable_file_name(output_dir, undefined_context): |
||
320 | """Verify correct error raised when file name cannot be rendered.""" |
||
321 | with pytest.raises(exceptions.UndefinedVariableInTemplate) as err: |
||
322 | generate.generate_files( |
||
323 | repo_dir='tests/undefined-variable/file-name/', |
||
324 | output_dir=output_dir, |
||
325 | context=undefined_context, |
||
326 | ) |
||
327 | error = err.value |
||
328 | assert "Unable to create file '{{cookiecutter.foobar}}'" == error.message |
||
329 | assert error.context == undefined_context |
||
330 | |||
331 | assert not Path(output_dir).joinpath('testproject').exists() |
||
332 | |||
333 | |||
334 | View Code Duplication | def test_raise_undefined_variable_file_name_existing_project( |
|
0 ignored issues
–
show
|
|||
335 | output_dir, undefined_context |
||
336 | ): |
||
337 | """Verify correct error raised when file name cannot be rendered.""" |
||
338 | testproj_path = Path(output_dir, 'testproject') |
||
339 | testproj_path.mkdir() |
||
340 | |||
341 | with pytest.raises(exceptions.UndefinedVariableInTemplate) as err: |
||
342 | generate.generate_files( |
||
343 | repo_dir='tests/undefined-variable/file-name/', |
||
344 | output_dir=output_dir, |
||
345 | context=undefined_context, |
||
346 | overwrite_if_exists=True, |
||
347 | ) |
||
348 | error = err.value |
||
349 | assert "Unable to create file '{{cookiecutter.foobar}}'" == error.message |
||
350 | assert error.context == undefined_context |
||
351 | |||
352 | assert testproj_path.exists() |
||
353 | |||
354 | |||
355 | def test_raise_undefined_variable_file_content(output_dir, undefined_context): |
||
356 | """Verify correct error raised when file content cannot be rendered.""" |
||
357 | with pytest.raises(exceptions.UndefinedVariableInTemplate) as err: |
||
358 | generate.generate_files( |
||
359 | repo_dir='tests/undefined-variable/file-content/', |
||
360 | output_dir=output_dir, |
||
361 | context=undefined_context, |
||
362 | ) |
||
363 | error = err.value |
||
364 | assert "Unable to create file 'README.rst'" == error.message |
||
365 | assert error.context == undefined_context |
||
366 | |||
367 | assert not Path(output_dir).joinpath('testproject').exists() |
||
368 | |||
369 | |||
370 | def test_raise_undefined_variable_dir_name(output_dir, undefined_context): |
||
371 | """Verify correct error raised when directory name cannot be rendered.""" |
||
372 | with pytest.raises(exceptions.UndefinedVariableInTemplate) as err: |
||
373 | generate.generate_files( |
||
374 | repo_dir='tests/undefined-variable/dir-name/', |
||
375 | output_dir=output_dir, |
||
376 | context=undefined_context, |
||
377 | ) |
||
378 | error = err.value |
||
379 | |||
380 | directory = Path('testproject', '{{cookiecutter.foobar}}') |
||
381 | msg = f"Unable to create directory '{directory}'" |
||
382 | assert msg == error.message |
||
383 | |||
384 | assert error.context == undefined_context |
||
385 | |||
386 | assert not Path(output_dir).joinpath('testproject').exists() |
||
387 | |||
388 | |||
389 | def test_keep_project_dir_on_failure(output_dir, undefined_context): |
||
390 | """Verify correct error raised when directory name cannot be rendered.""" |
||
391 | with pytest.raises(exceptions.UndefinedVariableInTemplate): |
||
392 | generate.generate_files( |
||
393 | repo_dir='tests/undefined-variable/dir-name/', |
||
394 | output_dir=output_dir, |
||
395 | context=undefined_context, |
||
396 | keep_project_on_failure=True, |
||
397 | ) |
||
398 | assert Path(output_dir).joinpath('testproject').exists() |
||
399 | |||
400 | |||
401 | View Code Duplication | def test_raise_undefined_variable_dir_name_existing_project( |
|
0 ignored issues
–
show
|
|||
402 | output_dir, undefined_context |
||
403 | ): |
||
404 | """Verify correct error raised when directory name cannot be rendered.""" |
||
405 | testproj_path = Path(output_dir, 'testproject') |
||
406 | testproj_path.mkdir() |
||
407 | |||
408 | with pytest.raises(exceptions.UndefinedVariableInTemplate) as err: |
||
409 | generate.generate_files( |
||
410 | repo_dir='tests/undefined-variable/dir-name/', |
||
411 | output_dir=output_dir, |
||
412 | context=undefined_context, |
||
413 | overwrite_if_exists=True, |
||
414 | ) |
||
415 | error = err.value |
||
416 | |||
417 | directory = Path('testproject', '{{cookiecutter.foobar}}') |
||
418 | msg = f"Unable to create directory '{directory}'" |
||
419 | assert msg == error.message |
||
420 | |||
421 | assert error.context == undefined_context |
||
422 | |||
423 | assert testproj_path.exists() |
||
424 | |||
425 | |||
426 | def test_raise_undefined_variable_project_dir(tmp_path): |
||
427 | """Verify correct error raised when directory name cannot be rendered.""" |
||
428 | with pytest.raises(exceptions.UndefinedVariableInTemplate) as err: |
||
429 | generate.generate_files( |
||
430 | repo_dir='tests/undefined-variable/dir-name/', |
||
431 | output_dir=tmp_path, |
||
432 | context={}, |
||
433 | ) |
||
434 | error = err.value |
||
435 | msg = "Unable to create project directory '{{cookiecutter.project_slug}}'" |
||
436 | assert msg == error.message |
||
437 | assert error.context == {} |
||
438 | |||
439 | assert not Path(tmp_path, 'testproject').exists() |
||
440 |