1# -*- coding: utf-8 -*- 2 3"""Tests for `generate_files` function and related errors raising. 4 5Use the global clean_system fixture and run additional teardown code to remove 6some special folders. 7 8For a better understanding - order of fixture calls: 9clean_system setup code 10remove_additional_folders setup code 11remove_additional_folders teardown code 12clean_system teardown code 13""" 14 15from __future__ import unicode_literals 16 17import io 18import os 19 20import pytest 21from binaryornot.check import is_binary 22from cookiecutter import exceptions, generate, utils 23 24 25@pytest.mark.parametrize('invalid_dirname', ['', '{foo}', '{{foo', 'bar}}']) 26def test_ensure_dir_is_templated_raises(invalid_dirname): 27 """Verify `ensure_dir_is_templated` raises on wrong directories names input.""" 28 with pytest.raises(exceptions.NonTemplatedInputDirException): 29 generate.ensure_dir_is_templated(invalid_dirname) 30 31 32@pytest.fixture(scope='function') 33def remove_additional_folders(): 34 """Remove some special folders which are created by the tests.""" 35 yield 36 if os.path.exists('inputpizzä'): 37 utils.rmtree('inputpizzä') 38 if os.path.exists('inputgreen'): 39 utils.rmtree('inputgreen') 40 if os.path.exists('inputbinary_files'): 41 utils.rmtree('inputbinary_files') 42 if os.path.exists('tests/custom_output_dir'): 43 utils.rmtree('tests/custom_output_dir') 44 if os.path.exists('inputpermissions'): 45 utils.rmtree('inputpermissions') 46 47 48@pytest.mark.usefixtures('clean_system', 'remove_additional_folders') 49def test_generate_files_nontemplated_exception(): 50 """ 51 Verify `generate_files` raises when no directories to render exist. 52 53 Note: Check `tests/test-generate-files-nontemplated` location to understand. 54 """ 55 with pytest.raises(exceptions.NonTemplatedInputDirException): 56 generate.generate_files( 57 context={'cookiecutter': {'food': 'pizza'}}, 58 repo_dir='tests/test-generate-files-nontemplated', 59 ) 60 61 62@pytest.mark.usefixtures('clean_system', 'remove_additional_folders') 63def test_generate_files(): 64 """Verify directory name correctly rendered with unicode containing context.""" 65 generate.generate_files( 66 context={'cookiecutter': {'food': 'pizzä'}}, 67 repo_dir='tests/test-generate-files', 68 ) 69 70 simple_file = 'inputpizzä/simple.txt' 71 assert os.path.isfile(simple_file) 72 73 simple_text = io.open(simple_file, 'rt', encoding='utf-8').read() 74 assert simple_text == u'I eat pizzä' 75 76 77@pytest.mark.usefixtures('clean_system', 'remove_additional_folders') 78def test_generate_files_with_trailing_newline(): 79 """Verify new line not removed by templating engine after folder generation.""" 80 generate.generate_files( 81 context={'cookiecutter': {'food': 'pizzä'}}, 82 repo_dir='tests/test-generate-files', 83 ) 84 85 newline_file = 'inputpizzä/simple-with-newline.txt' 86 assert os.path.isfile(newline_file) 87 88 with io.open(newline_file, 'r', encoding='utf-8') as f: 89 simple_text = f.read() 90 assert simple_text == u'I eat pizzä\n' 91 92 93@pytest.mark.usefixtures('clean_system', 'remove_additional_folders') 94def test_generate_files_binaries(): 95 """Verify binary files created during directory generation.""" 96 generate.generate_files( 97 context={'cookiecutter': {'binary_test': 'binary_files'}}, 98 repo_dir='tests/test-generate-binaries', 99 ) 100 101 assert is_binary('inputbinary_files/logo.png') 102 assert is_binary('inputbinary_files/.DS_Store') 103 assert not is_binary('inputbinary_files/readme.txt') 104 assert is_binary('inputbinary_files/some_font.otf') 105 assert is_binary('inputbinary_files/binary_files/logo.png') 106 assert is_binary('inputbinary_files/binary_files/.DS_Store') 107 assert not is_binary('inputbinary_files/binary_files/readme.txt') 108 assert is_binary('inputbinary_files/binary_files/some_font.otf') 109 assert is_binary('inputbinary_files/binary_files/binary_files/logo.png') 110 111 112@pytest.mark.usefixtures('clean_system', 'remove_additional_folders') 113def test_generate_files_absolute_path(): 114 """Verify usage of `abspath` does not change files generation behaviour.""" 115 generate.generate_files( 116 context={'cookiecutter': {'food': 'pizzä'}}, 117 repo_dir=os.path.abspath('tests/test-generate-files'), 118 ) 119 assert os.path.isfile('inputpizzä/simple.txt') 120 121 122@pytest.mark.usefixtures('clean_system', 'remove_additional_folders') 123def test_generate_files_output_dir(): 124 """Verify `output_dir` option for `generate_files` changing location correctly.""" 125 os.mkdir('tests/custom_output_dir') 126 project_dir = generate.generate_files( 127 context={'cookiecutter': {'food': 'pizzä'}}, 128 repo_dir=os.path.abspath('tests/test-generate-files'), 129 output_dir='tests/custom_output_dir', 130 ) 131 assert os.path.isfile('tests/custom_output_dir/inputpizzä/simple.txt') 132 assert project_dir == os.path.abspath('tests/custom_output_dir/inputpizzä') 133 134 135@pytest.mark.usefixtures('clean_system', 'remove_additional_folders') 136def test_generate_files_permissions(): 137 """Verify generates files respect source files permissions. 138 139 simple.txt and script.sh should retain their respective 0o644 and 0o755 140 permissions. 141 """ 142 generate.generate_files( 143 context={'cookiecutter': {'permissions': 'permissions'}}, 144 repo_dir='tests/test-generate-files-permissions', 145 ) 146 147 assert os.path.isfile('inputpermissions/simple.txt') 148 149 # simple.txt should still be 0o644 150 tests_simple_file = os.path.join( 151 'tests', 152 'test-generate-files-permissions', 153 'input{{cookiecutter.permissions}}', 154 'simple.txt', 155 ) 156 tests_simple_file_mode = os.stat(tests_simple_file).st_mode & 0o777 157 158 input_simple_file = os.path.join('inputpermissions', 'simple.txt') 159 input_simple_file_mode = os.stat(input_simple_file).st_mode & 0o777 160 assert tests_simple_file_mode == input_simple_file_mode 161 162 assert os.path.isfile('inputpermissions/script.sh') 163 164 # script.sh should still be 0o755 165 tests_script_file = os.path.join( 166 'tests', 167 'test-generate-files-permissions', 168 'input{{cookiecutter.permissions}}', 169 'script.sh', 170 ) 171 tests_script_file_mode = os.stat(tests_script_file).st_mode & 0o777 172 173 input_script_file = os.path.join('inputpermissions', 'script.sh') 174 input_script_file_mode = os.stat(input_script_file).st_mode & 0o777 175 assert tests_script_file_mode == input_script_file_mode 176 177 178@pytest.mark.usefixtures('clean_system', 'remove_additional_folders') 179def test_generate_files_with_overwrite_if_exists_with_skip_if_file_exists(): 180 """Verify `skip_if_file_exist` has priority over `overwrite_if_exists`.""" 181 simple_file = 'inputpizzä/simple.txt' 182 simple_with_new_line_file = 'inputpizzä/simple-with-newline.txt' 183 184 os.makedirs('inputpizzä') 185 with open(simple_file, 'w') as f: 186 f.write('temp') 187 188 generate.generate_files( 189 context={'cookiecutter': {'food': 'pizzä'}}, 190 repo_dir='tests/test-generate-files', 191 overwrite_if_exists=True, 192 skip_if_file_exists=True, 193 ) 194 195 assert os.path.isfile(simple_file) 196 assert os.path.isfile(simple_with_new_line_file) 197 198 simple_text = io.open(simple_file, 'rt', encoding='utf-8').read() 199 assert simple_text == u'temp' 200 201 202@pytest.mark.usefixtures('clean_system', 'remove_additional_folders') 203def test_generate_files_with_skip_if_file_exists(): 204 """Verify existed files not removed if error raised with `skip_if_file_exists`.""" 205 simple_file = 'inputpizzä/simple.txt' 206 simple_with_new_line_file = 'inputpizzä/simple-with-newline.txt' 207 208 os.makedirs('inputpizzä') 209 with open(simple_file, 'w') as f: 210 f.write('temp') 211 212 with pytest.raises(exceptions.OutputDirExistsException): 213 generate.generate_files( 214 context={'cookiecutter': {'food': 'pizzä'}}, 215 repo_dir='tests/test-generate-files', 216 skip_if_file_exists=True, 217 ) 218 219 assert os.path.isfile(simple_file) 220 assert not os.path.exists(simple_with_new_line_file) 221 222 simple_text = io.open(simple_file, 'rt', encoding='utf-8').read() 223 assert simple_text == u'temp' 224 225 226@pytest.mark.usefixtures('clean_system', 'remove_additional_folders') 227def test_generate_files_with_overwrite_if_exists(): 228 """Verify overwrite_if_exists overwrites old files.""" 229 simple_file = 'inputpizzä/simple.txt' 230 simple_with_new_line_file = 'inputpizzä/simple-with-newline.txt' 231 232 os.makedirs('inputpizzä') 233 with open(simple_file, 'w') as f: 234 f.write('temp') 235 236 generate.generate_files( 237 context={'cookiecutter': {'food': 'pizzä'}}, 238 repo_dir='tests/test-generate-files', 239 overwrite_if_exists=True, 240 ) 241 242 assert os.path.isfile(simple_file) 243 assert os.path.isfile(simple_with_new_line_file) 244 245 simple_text = io.open(simple_file, 'rt', encoding='utf-8').read() 246 assert simple_text == u'I eat pizzä' 247 248 249@pytest.fixture 250def undefined_context(): 251 """Fixture. Populate context variable for future tests.""" 252 return { 253 'cookiecutter': {'project_slug': 'testproject', 'github_username': 'hackebrot'} 254 } 255 256 257def test_raise_undefined_variable_file_name(tmpdir, undefined_context): 258 """Verify correct error raised when file name cannot be rendered.""" 259 output_dir = tmpdir.mkdir('output') 260 261 with pytest.raises(exceptions.UndefinedVariableInTemplate) as err: 262 generate.generate_files( 263 repo_dir='tests/undefined-variable/file-name/', 264 output_dir=str(output_dir), 265 context=undefined_context, 266 ) 267 error = err.value 268 assert "Unable to create file '{{cookiecutter.foobar}}'" == error.message 269 assert error.context == undefined_context 270 271 assert not output_dir.join('testproject').exists() 272 273 274def test_raise_undefined_variable_file_name_existing_project(tmpdir, undefined_context): 275 """Verify correct error raised when file name cannot be rendered.""" 276 output_dir = tmpdir.mkdir('output') 277 278 output_dir.join('testproject').mkdir() 279 280 with pytest.raises(exceptions.UndefinedVariableInTemplate) as err: 281 generate.generate_files( 282 repo_dir='tests/undefined-variable/file-name/', 283 output_dir=str(output_dir), 284 context=undefined_context, 285 overwrite_if_exists=True, 286 ) 287 error = err.value 288 assert "Unable to create file '{{cookiecutter.foobar}}'" == error.message 289 assert error.context == undefined_context 290 291 assert output_dir.join('testproject').exists() 292 293 294def test_raise_undefined_variable_file_content(tmpdir, undefined_context): 295 """Verify correct error raised when file content cannot be rendered.""" 296 output_dir = tmpdir.mkdir('output') 297 298 with pytest.raises(exceptions.UndefinedVariableInTemplate) as err: 299 generate.generate_files( 300 repo_dir='tests/undefined-variable/file-content/', 301 output_dir=str(output_dir), 302 context=undefined_context, 303 ) 304 error = err.value 305 assert "Unable to create file 'README.rst'" == error.message 306 assert error.context == undefined_context 307 308 assert not output_dir.join('testproject').exists() 309 310 311def test_raise_undefined_variable_dir_name(tmpdir, undefined_context): 312 """Verify correct error raised when directory name cannot be rendered.""" 313 output_dir = tmpdir.mkdir('output') 314 315 with pytest.raises(exceptions.UndefinedVariableInTemplate) as err: 316 generate.generate_files( 317 repo_dir='tests/undefined-variable/dir-name/', 318 output_dir=str(output_dir), 319 context=undefined_context, 320 ) 321 error = err.value 322 323 directory = os.path.join('testproject', '{{cookiecutter.foobar}}') 324 msg = "Unable to create directory '{}'".format(directory) 325 assert msg == error.message 326 327 assert error.context == undefined_context 328 329 assert not output_dir.join('testproject').exists() 330 331 332def test_raise_undefined_variable_dir_name_existing_project(tmpdir, undefined_context): 333 """Verify correct error raised when directory name cannot be rendered.""" 334 output_dir = tmpdir.mkdir('output') 335 336 output_dir.join('testproject').mkdir() 337 338 with pytest.raises(exceptions.UndefinedVariableInTemplate) as err: 339 generate.generate_files( 340 repo_dir='tests/undefined-variable/dir-name/', 341 output_dir=str(output_dir), 342 context=undefined_context, 343 overwrite_if_exists=True, 344 ) 345 error = err.value 346 347 directory = os.path.join('testproject', '{{cookiecutter.foobar}}') 348 msg = "Unable to create directory '{}'".format(directory) 349 assert msg == error.message 350 351 assert error.context == undefined_context 352 353 assert output_dir.join('testproject').exists() 354 355 356def test_raise_undefined_variable_project_dir(tmpdir): 357 """Verify correct error raised when directory name cannot be rendered.""" 358 output_dir = tmpdir.mkdir('output') 359 360 with pytest.raises(exceptions.UndefinedVariableInTemplate) as err: 361 generate.generate_files( 362 repo_dir='tests/undefined-variable/dir-name/', 363 output_dir=str(output_dir), 364 context={}, 365 ) 366 error = err.value 367 msg = "Unable to create project directory '{{cookiecutter.project_slug}}'" 368 assert msg == error.message 369 assert error.context == {} 370 371 assert not output_dir.join('testproject').exists() 372