perf/pixel-rate: new pixel throughput microbenchmark
[piglit.git] / unittests / framework / test_core.py
blobde55f902eecdf226e875540e9e3f5b70f1294b4b
1 # coding=utf-8
2 # Copyright (c) 2014, 2016, 2019 Intel Corporation
4 # Permission is hereby granted, free of charge, to any person obtaining a copy
5 # of this software and associated documentation files (the "Software"), to deal
6 # in the Software without restriction, including without limitation the rights
7 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 # copies of the Software, and to permit persons to whom the Software is
9 # furnished to do so, subject to the following conditions:
11 # The above copyright notice and this permission notice shall be included in
12 # all copies or substantial portions of the Software.
14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 # SOFTWARE.
22 """ Module providing tests for the core module """
24 import collections
25 import errno
26 import os
27 import textwrap
28 from unittest import mock
30 import pytest
32 from framework import core
33 from framework import exceptions
35 from . import skip
37 # Making good test names often flies in the face of PEP8 recommendations, ignore
38 # those
39 # pylint: disable=invalid-name
41 # For testing purposes (and to get good names) it's useful to use classes for
42 # grouping tests. Often these tests share no state, which would be bad if they
43 # were not tests, but that's kind of the way python testing works.
44 # pylint: disable=no-self-use
47 class TestParseListfile(object):
48 """Tests for core.parse_listfile."""
50 def test_parse_listfile_return(self, tmpdir):
51 """core.parse_listfile(): returns a list-like object.
53 Given a file with a newline separated list of results, parse_listfile
54 should return a list of files with no whitespace.
55 """
56 f = tmpdir.join('test.list')
57 f.write("/tmp/foo\n/tmp/bar\n")
58 results = core.parse_listfile(str(f))
59 assert isinstance(results, collections.abc.Container)
61 def test_parse_listfile_whitespace(self, tmpdir):
62 """parse_listfile should remove various kinds of trailing whitespace.
64 It is important it doesn't touch whitespace in lines, however.
65 """
66 f = tmpdir.join('test.list')
67 f.write(textwrap.dedent("""\
68 space between
69 tab\t
70 space
71 newline
72 """))
73 results = core.parse_listfile(str(f))
75 assert results[0] == 'space between'
76 assert results[1] == 'tab'
77 assert results[2] == 'space'
78 assert results[3] == 'newline'
80 def test_parse_listfile_tilde_posix(self, tmpdir):
81 """core.parse_listfile(): tildes (~) are properly expanded.
83 According to the python docs for python 2.7
84 (http://docs.python.org/2/library/os.path.html#module-os.path), both
85 os.path.expanduser and os.path.expandvars work on both *nix systems
86 (Linux, *BSD, OSX) and Windows.
87 """
88 if os.name == 'posix':
89 expected = os.path.expandvars('$HOME')
90 else:
91 expected = os.path.expandvars('%USERPROFILE%')
92 expected = os.path.normpath(os.path.join(expected, 'foo'))
94 f = tmpdir.join('test.list')
95 f.write("~/foo\n")
96 results = core.parse_listfile(str(f))
97 assert os.path.normpath(results[0]) == expected
100 class TestGetConfig(object):
101 """Tests for core.get_config."""
102 _CONF_FILE = textwrap.dedent("""\
103 [nose-test]
104 ; a section for testing behavior
105 dir = foo""")
107 @skip.linux
108 def test_config_in_xdg_config_home(self, tmpdir, mocker):
109 """core.get_config() finds $XDG_CONFIG_HOME/piglit.conf"""
110 env = mocker.patch('framework.core.os.environ', new={})
111 env['XDG_CONFIG_HOME'] = str(tmpdir)
112 conf = tmpdir.join('piglit.conf')
113 conf.write(self._CONF_FILE)
114 core.get_config()
116 assert core.PIGLIT_CONFIG.has_section('nose-test')
118 @skip.linux
119 def test_config_in_home_dir(self, tmpdir, mocker):
120 """core.get_config() finds $HOME/.config/piglit.conf"""
121 env = mocker.patch('framework.core.os.environ', new={})
122 env['HOME'] = str(tmpdir)
123 conf = tmpdir.join('piglit.conf')
124 conf.write(self._CONF_FILE)
125 core.get_config()
127 assert core.PIGLIT_CONFIG.has_section('nose-test')
129 def test_config_in_current(self, tmpdir, mocker):
130 """core.get_config() finds ./piglit.conf"""
131 mocker.patch('framework.core.os.environ', new={})
132 conf = tmpdir.join('piglit.conf')
133 conf.write(self._CONF_FILE)
135 ret = tmpdir.chdir()
136 try:
137 core.get_config()
138 finally:
139 os.chdir(str(ret))
141 assert core.PIGLIT_CONFIG.has_section('nose-test')
143 def test_config_in_piglit_root(self, mocker, tmpdir):
144 """core.get_config() finds "piglit root"/piglit.conf"""
145 # Mock the __file__ attribute of the core module, since that's how
146 # piglit decides where the root of the piglit directory is.
147 mocker.patch('framework.core.__file__',
148 str(tmpdir.join('framework', 'core.py')))
149 mocker.patch('framework.core.os.environ', new={})
150 conf = tmpdir.join('piglit.conf')
151 conf.write(self._CONF_FILE)
152 core.get_config()
154 assert core.PIGLIT_CONFIG.has_section('nose-test')
157 class TestPiglitConfig(object):
158 """Tests for PiglitConfig methods."""
159 @classmethod
160 def setup_class(cls):
161 cls.conf = core.PiglitConfig()
162 cls.conf.add_section('set')
163 cls.conf.set('set', 'options', 'bool')
165 def test_safe_get_valid(self):
166 """core.PiglitConfig: safe_get returns a value if its in the Config."""
167 assert self.conf.safe_get('set', 'options') == 'bool'
169 def test_PiglitConfig_required_get_valid(self):
170 """core.PiglitConfig: required_get returns a value if its in the
171 Config."""
172 assert self.conf.required_get('set', 'options') == 'bool'
174 def test_safe_get_missing_option(self):
175 """core.PiglitConfig: safe_get returns None if the option is missing.
177 assert self.conf.safe_get('set', 'invalid') is None
179 def test_safe_get_missing_section(self):
180 """core.PiglitConfig: safe_get returns None if the section is missing.
182 assert self.conf.safe_get('invalid', 'invalid') is None
184 def test_required_get_missing_option(self):
185 """core.PiglitConfig: required_get raises PiglitFatalError if the
186 option is missing."""
187 with pytest.raises(exceptions.PiglitFatalError):
188 self.conf.required_get('set', 'invalid')
190 def test_required_get_missing_section(self):
191 """core.PiglitConfig: required_get raises PiglitFatalError if the
192 section is missing."""
193 with pytest.raises(exceptions.PiglitFatalError):
194 self.conf.required_get('invalid', 'invalid')
196 def test_safe_get_fallback(self):
197 """core.PiglitConfig: safe_get returns the value of fallback when the
198 section or option is missing."""
199 assert self.conf.safe_get('invalid', 'invalid', fallback='foo') == 'foo'
202 class TestGetOptions(object):
203 """Tests for the get_option function."""
205 @pytest.fixture
206 def env(self, mocker):
207 """Create a mocked os.environ."""
208 return mocker.patch('framework.core.os.environ', {})
210 @pytest.fixture
211 def conf(self, mocker):
212 """Create a mocked piglit.conf."""
213 return mocker.patch('framework.core.PIGLIT_CONFIG.safe_get',
214 mocker.Mock(return_value=None))
216 def test_from_default(self):
217 """core.get_option: if env is set it overrides piglit.conf."""
218 # The mock means that only the first value matters
219 actual = core.get_option('foo', ('foo', 'foo'),
220 default=mock.sentinel.good)
222 assert actual is mock.sentinel.good
224 def test_from_conf(self, conf):
225 """core.get_option: if env is not set a value is taken from
226 piglit.conf.
228 conf.return_value = mock.sentinel
230 # The mock means that these values don't actually matter
231 actual = core.get_option('foo', ('foo', 'foo'))
233 assert actual is mock.sentinel
235 def test_from_env(self, env, conf):
236 """core.get_option: if env is set it overrides piglit.conf."""
237 conf.return_value = mock.sentinel.bad
238 env['TEST'] = mock.sentinel.good
240 # The mock means that only the first value matters
241 actual = core.get_option('TEST', ('foo', 'foo'))
243 assert actual is mock.sentinel.good
245 def test_get_option_required(self, mocker):
246 """core.get_option: dies if a required option cannot be retrieved."""
247 mocker.patch('framework.core.os.environ', {}, True)
249 with pytest.raises(exceptions.PiglitFatalError):
250 core.get_option('NOT_REAL', ('fake', 'fake'), default='',
251 required=True)
254 class TestCheckDir(object):
255 """Tests for core.check_dir."""
257 def test_exists_fail(self, mocker, tmpdir):
258 """core.check_dir: if the directory exists and failifexsits is True
259 fail."""
260 tmpdir.chdir()
261 mocker.patch('framework.core.os.stat', mocker.Mock(side_effect=OSError))
262 with pytest.raises(exceptions.PiglitException):
263 core.check_dir('foo', True)
265 def test_not_exists_and_not_fail(self, mocker, tmpdir):
266 """core.check_dir: if the directory doesn't exists (ENOENT) and
267 failifexists is False continue."""
268 tmpdir.chdir()
269 mocker.patch('framework.core.os.stat',
270 mocker.Mock(side_effect=OSError('foo', errno.ENOENT)))
271 makedirs = mocker.patch('framework.core.os.makedirs')
273 core.check_dir('foo', False)
275 assert makedirs.called == 1
277 def test_exists_and_not_fail(self, mocker, tmpdir):
278 """core.check_dir: If makedirs fails with EEXIST pass"""
279 tmpdir.chdir()
280 mocker.patch('framework.core.os.stat', mocker.Mock())
281 makedirs = mocker.patch(
282 'framework.core.os.makedirs',
283 mocker.Mock(side_effect=OSError(errno.EEXIST, 'foo')))
285 core.check_dir('foo', False)
287 assert makedirs.called == 0
289 def test_makedirs_fail(self, mocker, tmpdir):
290 """core.check_dir: If makedirs fails with any other raise that error."""
291 tmpdir.chdir()
292 mocker.patch('framework.core.os.makedirs',
293 mocker.Mock(side_effect=OSError))
295 with pytest.raises(OSError):
296 core.check_dir('foo', False)
298 def test_handler(self, mocker, tmpdir):
299 """core.check_dir: Handler is called if not failifexists."""
300 class Sentinel(Exception):
301 pass
303 tmpdir.chdir()
305 mocker.patch('framework.core.os.stat',
306 mocker.Mock(side_effect=OSError('foo', errno.ENOTDIR)))
307 with pytest.raises(Sentinel):
308 core.check_dir('foo', handler=mocker.Mock(side_effect=Sentinel))
310 def test_stat_FileNotFoundError(self, mocker, tmpdir):
311 """core.check_dir: FileNotFoundError is raised and failifexsits is
312 False continue."""
313 tmpdir.chdir()
314 mocker.patch('framework.core.os.stat',
315 mocker.Mock(side_effect=FileNotFoundError))
316 makedirs = mocker.patch('framework.core.os.makedirs')
318 core.check_dir('foo', False)
320 assert makedirs.called == 1