1"""Tests for all things related to the configuration
2"""
3
4import pytest
5from mock import MagicMock
6
7from pip._internal.configuration import get_configuration_files, kinds
8from pip._internal.exceptions import ConfigurationError
9from tests.lib.configuration_helpers import ConfigurationMixin
10
11
12class TestConfigurationLoading(ConfigurationMixin):
13
14    def test_global_loading(self):
15        self.patch_configuration(kinds.GLOBAL, {"test.hello": "1"})
16
17        self.configuration.load()
18        assert self.configuration.get_value("test.hello") == "1"
19
20    def test_user_loading(self):
21        self.patch_configuration(kinds.USER, {"test.hello": "2"})
22
23        self.configuration.load()
24        assert self.configuration.get_value("test.hello") == "2"
25
26    def test_site_loading(self):
27        self.patch_configuration(kinds.SITE, {"test.hello": "3"})
28
29        self.configuration.load()
30        assert self.configuration.get_value("test.hello") == "3"
31
32    def test_environment_config_loading(self, monkeypatch):
33        contents = """
34            [test]
35            hello = 4
36        """
37
38        with self.tmpfile(contents) as config_file:
39            monkeypatch.setenv("PIP_CONFIG_FILE", config_file)
40
41            self.configuration.load()
42            assert self.configuration.get_value("test.hello") == "4", \
43                self.configuration._config
44
45    def test_environment_var_loading(self, monkeypatch):
46        monkeypatch.setenv("PIP_HELLO", "5")
47
48        self.configuration.load()
49        assert self.configuration.get_value(":env:.hello") == "5"
50
51    @pytest.mark.skipif("sys.platform == 'win32'")
52    def test_environment_var_does_not_load_lowercase(self, monkeypatch):
53        monkeypatch.setenv("pip_hello", "5")
54
55        self.configuration.load()
56        with pytest.raises(ConfigurationError):
57            self.configuration.get_value(":env:.hello")
58
59    def test_environment_var_does_not_load_version(self, monkeypatch):
60        monkeypatch.setenv("PIP_VERSION", "True")
61
62        self.configuration.load()
63
64        with pytest.raises(ConfigurationError):
65            self.configuration.get_value(":env:.version")
66
67    def test_environment_config_errors_if_malformed(self, monkeypatch):
68        contents = """
69            test]
70            hello = 4
71        """
72        with self.tmpfile(contents) as config_file:
73            monkeypatch.setenv("PIP_CONFIG_FILE", config_file)
74            with pytest.raises(ConfigurationError) as err:
75                self.configuration.load()
76
77        assert "section header" in str(err.value)  # error kind
78        assert "1" in str(err.value)  # line number
79        assert (  # file name
80            config_file in str(err.value) or
81            repr(config_file) in str(err.value)
82        )
83
84
85class TestConfigurationPrecedence(ConfigurationMixin):
86    # Tests for methods to that determine the order of precedence of
87    # configuration options
88
89    def test_env_overides_site(self):
90        self.patch_configuration(kinds.SITE, {"test.hello": "1"})
91        self.patch_configuration(kinds.ENV, {"test.hello": "0"})
92        self.configuration.load()
93
94        assert self.configuration.get_value("test.hello") == "0"
95
96    def test_env_overides_user(self):
97        self.patch_configuration(kinds.USER, {"test.hello": "2"})
98        self.patch_configuration(kinds.ENV, {"test.hello": "0"})
99        self.configuration.load()
100
101        assert self.configuration.get_value("test.hello") == "0"
102
103    def test_env_overides_global(self):
104        self.patch_configuration(kinds.GLOBAL, {"test.hello": "3"})
105        self.patch_configuration(kinds.ENV, {"test.hello": "0"})
106        self.configuration.load()
107
108        assert self.configuration.get_value("test.hello") == "0"
109
110    def test_site_overides_user(self):
111        self.patch_configuration(kinds.USER, {"test.hello": "2"})
112        self.patch_configuration(kinds.SITE, {"test.hello": "1"})
113        self.configuration.load()
114
115        assert self.configuration.get_value("test.hello") == "1"
116
117    def test_site_overides_global(self):
118        self.patch_configuration(kinds.GLOBAL, {"test.hello": "3"})
119        self.patch_configuration(kinds.SITE, {"test.hello": "1"})
120        self.configuration.load()
121
122        assert self.configuration.get_value("test.hello") == "1"
123
124    def test_user_overides_global(self):
125        self.patch_configuration(kinds.GLOBAL, {"test.hello": "3"})
126        self.patch_configuration(kinds.USER, {"test.hello": "2"})
127        self.configuration.load()
128
129        assert self.configuration.get_value("test.hello") == "2"
130
131    def test_env_not_overriden_by_environment_var(self, monkeypatch):
132        self.patch_configuration(kinds.ENV, {"test.hello": "1"})
133        monkeypatch.setenv("PIP_HELLO", "5")
134
135        self.configuration.load()
136
137        assert self.configuration.get_value("test.hello") == "1"
138        assert self.configuration.get_value(":env:.hello") == "5"
139
140    def test_site_not_overriden_by_environment_var(self, monkeypatch):
141        self.patch_configuration(kinds.SITE, {"test.hello": "2"})
142        monkeypatch.setenv("PIP_HELLO", "5")
143
144        self.configuration.load()
145
146        assert self.configuration.get_value("test.hello") == "2"
147        assert self.configuration.get_value(":env:.hello") == "5"
148
149    def test_user_not_overriden_by_environment_var(self, monkeypatch):
150        self.patch_configuration(kinds.USER, {"test.hello": "3"})
151        monkeypatch.setenv("PIP_HELLO", "5")
152
153        self.configuration.load()
154
155        assert self.configuration.get_value("test.hello") == "3"
156        assert self.configuration.get_value(":env:.hello") == "5"
157
158    def test_global_not_overriden_by_environment_var(self, monkeypatch):
159        self.patch_configuration(kinds.GLOBAL, {"test.hello": "4"})
160        monkeypatch.setenv("PIP_HELLO", "5")
161
162        self.configuration.load()
163
164        assert self.configuration.get_value("test.hello") == "4"
165        assert self.configuration.get_value(":env:.hello") == "5"
166
167
168class TestConfigurationModification(ConfigurationMixin):
169    # Tests for methods to that modify the state of a Configuration
170
171    def test_no_specific_given_modification(self):
172        self.configuration.load()
173
174        try:
175            self.configuration.set_value("test.hello", "10")
176        except ConfigurationError:
177            pass
178        else:
179            assert False, "Should have raised an error."
180
181    def test_site_modification(self):
182        self.configuration.load_only = kinds.SITE
183        self.configuration.load()
184
185        # Mock out the method
186        mymock = MagicMock(spec=self.configuration._mark_as_modified)
187        self.configuration._mark_as_modified = mymock
188
189        self.configuration.set_value("test.hello", "10")
190
191        # get the path to site config file
192        assert mymock.call_count == 1
193        assert mymock.call_args[0][0] == (
194            get_configuration_files()[kinds.SITE][0]
195        )
196
197    def test_user_modification(self):
198        # get the path to local config file
199        self.configuration.load_only = kinds.USER
200        self.configuration.load()
201
202        # Mock out the method
203        mymock = MagicMock(spec=self.configuration._mark_as_modified)
204        self.configuration._mark_as_modified = mymock
205
206        self.configuration.set_value("test.hello", "10")
207
208        # get the path to user config file
209        assert mymock.call_count == 1
210        assert mymock.call_args[0][0] == (
211            # Use new config file
212            get_configuration_files()[kinds.USER][1]
213        )
214
215    def test_global_modification(self):
216        # get the path to local config file
217        self.configuration.load_only = kinds.GLOBAL
218        self.configuration.load()
219
220        # Mock out the method
221        mymock = MagicMock(spec=self.configuration._mark_as_modified)
222        self.configuration._mark_as_modified = mymock
223
224        self.configuration.set_value("test.hello", "10")
225
226        # get the path to user config file
227        assert mymock.call_count == 1
228        assert mymock.call_args[0][0] == (
229            get_configuration_files()[kinds.GLOBAL][-1]
230        )
231