tests.conftest.restore_backup_dir()   B
last analyzed

Complexity

Conditions 7

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 11
dl 0
loc 18
rs 8
c 0
b 0
f 0
cc 7
nop 3
1
"""pytest fixtures which are globally available throughout the suite."""
2
import os
3
import shutil
4
5
import pytest
6
7
from cookiecutter import utils
8
from cookiecutter.config import DEFAULT_CONFIG
9
10
11
USER_CONFIG = """
12
cookiecutters_dir: '{cookiecutters_dir}'
13
replay_dir: '{replay_dir}'
14
"""
15
16
17
@pytest.fixture(autouse=True)
18
def isolated_filesystem(monkeypatch, tmp_path):
19
    """Ensure filesystem isolation, set the user home to a tmp_path."""
20
    root_path = tmp_path.joinpath("home")
21
    root_path.mkdir()
22
    cookiecutters_dir = root_path.joinpath(".cookiecutters/")
23
    replay_dir = root_path.joinpath(".cookiecutter_replay/")
24
    monkeypatch.setitem(DEFAULT_CONFIG, 'cookiecutters_dir', str(cookiecutters_dir))
25
    monkeypatch.setitem(DEFAULT_CONFIG, 'replay_dir', str(replay_dir))
26
27
    monkeypatch.setenv("HOME", str(root_path))
28
    monkeypatch.setenv("USERPROFILE", str(root_path))
29
30
31
def backup_dir(original_dir, backup_dir):
32
    """Generate backup directory based on original directory."""
33
    # If the default original_dir is pre-existing, move it to a temp location
34
    if not os.path.isdir(original_dir):
35
        return False
36
37
    # Remove existing stale backups before backing up.
38
    if os.path.isdir(backup_dir):
39
        utils.rmtree(backup_dir)
40
41
    shutil.copytree(original_dir, backup_dir)
42
    return True
43
44
45
def restore_backup_dir(original_dir, backup_dir, original_dir_found):
46
    """Restore default contents."""
47
    original_dir_is_dir = os.path.isdir(original_dir)
48
    if original_dir_found:
49
        # Delete original_dir if a backup exists
50
        if original_dir_is_dir and os.path.isdir(backup_dir):
51
            utils.rmtree(original_dir)
52
    else:
53
        # Delete the created original_dir.
54
        # There's no backup because it never existed
55
        if original_dir_is_dir:
56
            utils.rmtree(original_dir)
57
58
    # Restore the user's default original_dir contents
59
    if os.path.isdir(backup_dir):
60
        shutil.copytree(backup_dir, original_dir)
61
    if os.path.isdir(original_dir):
62
        utils.rmtree(backup_dir)
63
64
65
@pytest.fixture(scope='function')
66
def clean_system(request):
67
    """Fixture. Simulates a clean system with no configured or cloned cookiecutters.
68
69
    It runs code which can be regarded as setup code as known from a unittest
70
    TestCase. Additionally it defines a local function referring to values
71
    which have been stored to local variables in the setup such as the location
72
    of the cookiecutters on disk. This function is registered as a teardown
73
    hook with `request.addfinalizer` at the very end of the fixture. Pytest
74
    runs the named hook as soon as the fixture is out of scope, when the test
75
    finished to put it another way.
76
77
    During setup:
78
79
    * Back up the `~/.cookiecutterrc` config file to `~/.cookiecutterrc.backup`
80
    * Back up the `~/.cookiecutters/` dir to `~/.cookiecutters.backup/`
81
    * Back up the `~/.cookiecutter_replay/` dir to
82
      `~/.cookiecutter_replay.backup/`
83
    * Starts off a test case with no pre-existing `~/.cookiecutterrc` or
84
      `~/.cookiecutters/` or `~/.cookiecutter_replay/`
85
86
    During teardown:
87
88
    * Delete `~/.cookiecutters/` only if a backup is present at
89
      `~/.cookiecutters.backup/`
90
    * Delete `~/.cookiecutter_replay/` only if a backup is present at
91
      `~/.cookiecutter_replay.backup/`
92
    * Restore the `~/.cookiecutterrc` config file from
93
      `~/.cookiecutterrc.backup`
94
    * Restore the `~/.cookiecutters/` dir from `~/.cookiecutters.backup/`
95
    * Restore the `~/.cookiecutter_replay/` dir from
96
      `~/.cookiecutter_replay.backup/`
97
98
    """
99
    # If ~/.cookiecutterrc is pre-existing, move it to a temp location
100
    user_config_path = os.path.expanduser('~/.cookiecutterrc')
101
    user_config_path_backup = os.path.expanduser('~/.cookiecutterrc.backup')
102
    if os.path.exists(user_config_path):
103
        user_config_found = True
104
        shutil.copy(user_config_path, user_config_path_backup)
105
        os.remove(user_config_path)
106
    else:
107
        user_config_found = False
108
109
    # If the default cookiecutters_dir is pre-existing, move it to a
110
    # temp location
111
    cookiecutters_dir = os.path.expanduser('~/.cookiecutters')
112
    cookiecutters_dir_backup = os.path.expanduser('~/.cookiecutters.backup')
113
    cookiecutters_dir_found = backup_dir(cookiecutters_dir, cookiecutters_dir_backup)
114
115
    # If the default cookiecutter_replay_dir is pre-existing, move it to a
116
    # temp location
117
    cookiecutter_replay_dir = os.path.expanduser('~/.cookiecutter_replay')
118
    cookiecutter_replay_dir_backup = os.path.expanduser('~/.cookiecutter_replay.backup')
119
    cookiecutter_replay_dir_found = backup_dir(
120
        cookiecutter_replay_dir, cookiecutter_replay_dir_backup
121
    )
122
123
    def restore_backup():
124
        # If it existed, restore ~/.cookiecutterrc
125
        # We never write to ~/.cookiecutterrc, so this logic is simpler.
126
        if user_config_found and os.path.exists(user_config_path_backup):
127
            shutil.copy(user_config_path_backup, user_config_path)
128
            os.remove(user_config_path_backup)
129
130
        # Carefully delete the created ~/.cookiecutters dir only in certain
131
        # conditions.
132
        restore_backup_dir(
133
            cookiecutters_dir, cookiecutters_dir_backup, cookiecutters_dir_found
134
        )
135
136
        # Carefully delete the created ~/.cookiecutter_replay dir only in
137
        # certain conditions.
138
        restore_backup_dir(
139
            cookiecutter_replay_dir,
140
            cookiecutter_replay_dir_backup,
141
            cookiecutter_replay_dir_found,
142
        )
143
144
    request.addfinalizer(restore_backup)
145
146
147
@pytest.fixture(scope='session')
148
def user_dir(tmp_path_factory):
149
    """Fixture that simulates the user's home directory."""
150
    return tmp_path_factory.mktemp('user_dir')
151
152
153
@pytest.fixture(scope='session')
154
def user_config_data(user_dir):
155
    """Fixture that creates 2 Cookiecutter user config dirs.
156
157
     It will create it in the user's home directory.
158
159
    * `cookiecutters_dir`
160
    * `cookiecutter_replay`
161
162
    :returns: Dict with name of both user config dirs
163
    """
164
    cookiecutters_dir = user_dir.joinpath('cookiecutters')
165
    cookiecutters_dir.mkdir()
166
    replay_dir = user_dir.joinpath('cookiecutter_replay')
167
    replay_dir.mkdir()
168
    return {
169
        'cookiecutters_dir': str(cookiecutters_dir),
170
        'replay_dir': str(replay_dir),
171
    }
172
173
174
@pytest.fixture(scope='session')
175
def user_config_file(user_dir, user_config_data):
176
    """Fixture that creates a config file called `config`.
177
178
     It will create it in the user's home directory, with YAML from
179
     `user_config_data`.
180
181
    :param user_dir: Simulated user's home directory
182
    :param user_config_data: Dict of config values
183
    :returns: String of path to config file
184
    """
185
    config_file = user_dir.joinpath('config')
186
187
    config_text = USER_CONFIG.format(**user_config_data)
188
    config_file.write_text(config_text)
189
    return str(config_file)
190
191
192
@pytest.fixture
193
def output_dir(tmp_path):
194
    """Fixture to prepare test output directory."""
195
    output_path = tmp_path.joinpath("output")
196
    output_path.mkdir()
197
    return str(output_path)
198
199
200
@pytest.fixture
201
def clone_dir(tmp_path):
202
    """Simulate creation of a directory called `clone_dir` inside of `tmp_path`. \
203
    Returns a str to said directory."""
204
    clone_dir = tmp_path.joinpath("clone_dir")
205
    clone_dir.mkdir()
206
    return clone_dir
207