Completed
Push — master ( b6e32d...508ef4 )
by Andrey
15s queued 13s
created

test_apply_overwrites_in_nested_dict()   A

Complexity

Conditions 1

Size

Total Lines 40
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 26
dl 0
loc 40
rs 9.256
c 0
b 0
f 0
cc 1
nop 0
1
"""Verify generate context behaviour and context overwrite priorities."""
2
import os
3
import re
4
from collections import OrderedDict
5
6
import pytest
7
8
from cookiecutter import generate
9
from cookiecutter.exceptions import ContextDecodingException
10
11
12
def context_data():
13
    """Generate pytest parametrization variables for test.
14
15
    Return ('input_params, expected_context') tuples.
16
    """
17
    context = (
18
        {'context_file': 'tests/test-generate-context/test.json'},
19
        {'test': {'1': 2, 'some_key': 'some_val'}},
20
    )
21
22
    context_with_default = (
23
        {
24
            'context_file': 'tests/test-generate-context/test.json',
25
            'default_context': {'1': 3},
26
        },
27
        {'test': {'1': 3, 'some_key': 'some_val'}},
28
    )
29
30
    context_with_extra = (
31
        {
32
            'context_file': 'tests/test-generate-context/test.json',
33
            'extra_context': {'1': 4},
34
        },
35
        {'test': {'1': 4, 'some_key': 'some_val'}},
36
    )
37
38
    context_with_default_and_extra = (
39
        {
40
            'context_file': 'tests/test-generate-context/test.json',
41
            'default_context': {'1': 3},
42
            'extra_context': {'1': 5},
43
        },
44
        {'test': {'1': 5, 'some_key': 'some_val'}},
45
    )
46
47
    yield context
48
    yield context_with_default
49
    yield context_with_extra
50
    yield context_with_default_and_extra
51
52
53
@pytest.mark.usefixtures('clean_system')
54
@pytest.mark.parametrize('input_params, expected_context', context_data())
55
def test_generate_context(input_params, expected_context):
56
    """Verify input contexts combinations result in expected content on output."""
57
    assert generate.generate_context(**input_params) == expected_context
58
59
60
@pytest.mark.usefixtures('clean_system')
61
def test_generate_context_with_json_decoding_error():
62
    """Verify malformed JSON file generates expected error output."""
63
    with pytest.raises(ContextDecodingException) as excinfo:
64
        generate.generate_context('tests/test-generate-context/invalid-syntax.json')
65
    # original message from json module should be included
66
    pattern = 'Expecting \'{0,1}:\'{0,1} delimiter: line 1 column (19|20) \\(char 19\\)'
67
    assert re.search(pattern, str(excinfo.value))
68
    # File name should be included too...for testing purposes, just test the
69
    # last part of the file. If we wanted to test the absolute path, we'd have
70
    # to do some additional work in the test which doesn't seem that needed at
71
    # this point.
72
    path = os.path.sep.join(['tests', 'test-generate-context', 'invalid-syntax.json'])
73
    assert path in str(excinfo.value)
74
75
76
def test_default_context_replacement_in_generate_context():
77
    """Verify default content settings are correctly replaced by template settings.
78
79
    Make sure that the default for list variables of `orientation` is based on
80
    the user config (`choices_template.json`) and not changed to a single value
81
    from `default_context`.
82
    """
83
    expected_context = {
84
        'choices_template': OrderedDict(
85
            [
86
                ('full_name', 'Raphael Pierzina'),
87
                ('github_username', 'hackebrot'),
88
                ('project_name', 'Kivy Project'),
89
                ('repo_name', '{{cookiecutter.project_name|lower}}'),
90
                ('orientation', ['landscape', 'all', 'portrait']),
91
            ]
92
        )
93
    }
94
95
    generated_context = generate.generate_context(
96
        context_file='tests/test-generate-context/choices_template.json',
97
        default_context={
98
            'not_in_template': 'foobar',
99
            'project_name': 'Kivy Project',
100
            'orientation': 'landscape',
101
        },
102
        extra_context={
103
            'also_not_in_template': 'foobar2',
104
            'github_username': 'hackebrot',
105
        },
106
    )
107
108
    assert generated_context == expected_context
109
110
111
def test_generate_context_decodes_non_ascii_chars():
112
    """Verify `generate_context` correctly decodes non-ascii chars."""
113
    expected_context = {
114
        'non_ascii': OrderedDict(
115
            [
116
                ('full_name', 'éèà'),
117
            ]
118
        )
119
    }
120
121
    generated_context = generate.generate_context(
122
        context_file='tests/test-generate-context/non_ascii.json'
123
    )
124
125
    assert generated_context == expected_context
126
127
128
@pytest.fixture
129
def template_context():
130
    """Fixture. Populates template content for future tests."""
131
    return OrderedDict(
132
        [
133
            ('full_name', 'Raphael Pierzina'),
134
            ('github_username', 'hackebrot'),
135
            ('project_name', 'Kivy Project'),
136
            ('repo_name', '{{cookiecutter.project_name|lower}}'),
137
            ('orientation', ['all', 'landscape', 'portrait']),
138
        ]
139
    )
140
141
142
def test_apply_overwrites_does_include_unused_variables(template_context):
143
    """Verify `apply_overwrites_to_context` skips variables that are not in context."""
144
    generate.apply_overwrites_to_context(
145
        context=template_context, overwrite_context={'not in template': 'foobar'}
146
    )
147
148
    assert 'not in template' not in template_context
149
150
151
def test_apply_overwrites_sets_non_list_value(template_context):
152
    """Verify `apply_overwrites_to_context` work with string variables."""
153
    generate.apply_overwrites_to_context(
154
        context=template_context, overwrite_context={'repo_name': 'foobar'}
155
    )
156
157
    assert template_context['repo_name'] == 'foobar'
158
159
160
def test_apply_overwrites_does_not_modify_choices_for_invalid_overwrite():
161
    """Verify variables overwrite for list if variable not in list ignored."""
162
    expected_context = {
163
        'choices_template': OrderedDict(
164
            [
165
                ('full_name', 'Raphael Pierzina'),
166
                ('github_username', 'hackebrot'),
167
                ('project_name', 'Kivy Project'),
168
                ('repo_name', '{{cookiecutter.project_name|lower}}'),
169
                ('orientation', ['all', 'landscape', 'portrait']),
170
            ]
171
        )
172
    }
173
174
    generated_context = generate.generate_context(
175
        context_file='tests/test-generate-context/choices_template.json',
176
        default_context={
177
            'not_in_template': 'foobar',
178
            'project_name': 'Kivy Project',
179
            'orientation': 'foobar',
180
        },
181
        extra_context={
182
            'also_not_in_template': 'foobar2',
183
            'github_username': 'hackebrot',
184
        },
185
    )
186
187
    assert generated_context == expected_context
188
189
190
def test_apply_overwrites_invalid_overwrite(template_context):
191
    """Verify variables overwrite for list if variable not in list not ignored."""
192
    with pytest.raises(ValueError):
193
        generate.apply_overwrites_to_context(
194
            context=template_context, overwrite_context={'orientation': 'foobar'}
195
        )
196
197
198
def test_apply_overwrites_sets_default_for_choice_variable(template_context):
199
    """Verify overwritten list member became a default value."""
200
    generate.apply_overwrites_to_context(
201
        context=template_context, overwrite_context={'orientation': 'landscape'}
202
    )
203
204
    assert template_context['orientation'] == ['landscape', 'all', 'portrait']
205
206
207
def test_apply_overwrites_in_nested_dict():
208
    """Verify nested dict in default content settings are correctly replaced."""
209
    expected_context = {
210
        'nested_dict': OrderedDict(
211
            [
212
                ('full_name', 'Raphael Pierzina'),
213
                ('github_username', 'hackebrot'),
214
                (
215
                    'project',
216
                    OrderedDict(
217
                        [
218
                            ('name', 'My Kivy Project'),
219
                            ('description', 'My Kivy Project'),
220
                            ('repo_name', '{{cookiecutter.project_name|lower}}'),
221
                            ('orientation', ["all", "landscape", "portrait"]),
222
                        ]
223
                    ),
224
                ),
225
            ]
226
        )
227
    }
228
229
    generated_context = generate.generate_context(
230
        context_file='tests/test-generate-context/nested_dict.json',
231
        default_context={
232
            'not_in_template': 'foobar',
233
            'project': {
234
                'description': 'My Kivy Project',
235
            },
236
        },
237
        extra_context={
238
            'also_not_in_template': 'foobar2',
239
            'github_username': 'hackebrot',
240
            'project': {
241
                'name': 'My Kivy Project',
242
            },
243
        },
244
    )
245
246
    assert generated_context == expected_context
247