1# Copyright 2015,2016 Nir Cohen
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import os
16import sys
17import ast
18import subprocess
19try:
20    from StringIO import StringIO  # Python 2.x
21except ImportError:
22    from io import StringIO  # Python 3.x
23
24import pytest
25
26
27BASE = os.path.abspath(os.path.dirname(__file__))
28RESOURCES = os.path.join(BASE, 'resources')
29DISTROS_DIR = os.path.join(RESOURCES, 'distros')
30TESTDISTROS = os.path.join(RESOURCES, 'testdistros')
31SPECIAL = os.path.join(RESOURCES, 'special')
32DISTROS = [dist for dist in os.listdir(DISTROS_DIR) if dist != '__shared__']
33
34
35IS_LINUX = sys.platform.startswith('linux')
36if IS_LINUX:
37    import distro
38
39    RELATIVE_UNIXCONFDIR = distro._UNIXCONFDIR[1:]
40    MODULE_DISTRO = distro._distro
41
42
43class TestNonLinuxPlatform:
44    """Obviously, this only tests Windows. Will add OS X tests on Travis
45    Later
46    """
47
48    def test_cant_use_on_windows(self):
49        try:
50            import distro  # NOQA
51        except ImportError as ex:
52            assert 'Unsupported platform' in str(ex)
53
54
55@pytest.mark.skipif(not IS_LINUX, reason='Irrelevant on non-linux')
56class TestCli:
57
58    def _parse(self, command):
59        sys.argv = command.split()
60        distro.main()
61
62    def _run(self, command):
63        stdout, _ = subprocess.Popen(
64            command,
65            stdout=subprocess.PIPE,
66            stderr=subprocess.PIPE).communicate()
67        # Need to decode or we get bytes in Python 3.x
68        return stdout.decode('utf-8')
69
70    def test_cli_for_coverage_yuch(self):
71        self._parse('distro')
72        self._parse('distro -j')
73
74    def test_cli(self):
75        command = [sys.executable, '-m', 'distro']
76        desired_output = 'Name: ' + distro.name(pretty=True)
77        distro_version = distro.version(pretty=True)
78        distro_codename = distro.codename()
79        desired_output += '\n' + 'Version: ' + distro_version
80        desired_output += '\n' + 'Codename: ' + distro_codename
81        desired_output += '\n'
82        assert self._run(command) == desired_output
83
84    def test_cli_json(self):
85        command = [sys.executable, '-m', 'distro', '-j']
86        assert ast.literal_eval(self._run(command)) == distro.info()
87
88
89@pytest.mark.skipif(not IS_LINUX, reason='Irrelevant on non-linux')
90class DistroTestCase(object):
91    """A base class for any testcase classes that test the distributions
92    represented in the `DISTROS` subtree.
93    """
94
95    def setup_method(self, test_method):
96        # The environment stays the same across all testcases, so we
97        # save and restore the PATH env var in each test case that
98        # changes it:
99        self._saved_path = os.environ["PATH"]
100        self._saved_UNIXCONFDIR = distro._UNIXCONFDIR
101
102    def teardown_method(self, test_method):
103        os.environ["PATH"] = self._saved_path
104        distro._UNIXCONFDIR = self._saved_UNIXCONFDIR
105
106    def _setup_for_distro(self, distro_root):
107        distro_bin = os.path.join(distro_root, 'bin')
108        # We don't want to pick up a possibly present lsb_release in the
109        # distro that runs this test, so we use a PATH with only one entry:
110        os.environ["PATH"] = distro_bin
111        distro._UNIXCONFDIR = os.path.join(distro_root, RELATIVE_UNIXCONFDIR)
112
113
114@pytest.mark.skipif(not IS_LINUX, reason='Irrelevant on non-linux')
115class TestOSRelease:
116
117    def setup_method(self, test_method):
118        dist = test_method.__name__.split('_')[1]
119        os_release = os.path.join(DISTROS_DIR, dist, 'etc', 'os-release')
120        self.distro = distro.LinuxDistribution(False, os_release, 'non')
121
122    def _test_outcome(self, outcome):
123        assert self.distro.id() == outcome.get('id', '')
124        assert self.distro.name() == outcome.get('name', '')
125        assert self.distro.name(pretty=True) == outcome.get('pretty_name', '')
126        assert self.distro.version() == outcome.get('version', '')
127        assert self.distro.version(pretty=True) == \
128            outcome.get('pretty_version', '')
129        assert self.distro.version(best=True) == \
130            outcome.get('best_version', '')
131        assert self.distro.like() == outcome.get('like', '')
132        assert self.distro.codename() == outcome.get('codename', '')
133
134    def test_arch_os_release(self):
135        desired_outcome = {
136            'id': 'arch',
137            'name': 'Arch Linux',
138            'pretty_name': 'Arch Linux',
139        }
140        self._test_outcome(desired_outcome)
141
142    def test_kali_os_release(self):
143        desired_outcome = {
144            'id': 'kali',
145            'name': 'Kali GNU/Linux',
146            'pretty_name': 'Kali GNU/Linux Rolling',
147            'version': '2017.1',
148            'pretty_version': '2017.1',
149            'best_version': '2017.1',
150            'like': 'debian'
151        }
152        self._test_outcome(desired_outcome)
153
154    def test_centos7_os_release(self):
155        desired_outcome = {
156            'id': 'centos',
157            'name': 'CentOS Linux',
158            'pretty_name': 'CentOS Linux 7 (Core)',
159            'version': '7',
160            'pretty_version': '7 (Core)',
161            'best_version': '7',
162            'like': 'rhel fedora',
163            'codename': 'Core'
164        }
165        self._test_outcome(desired_outcome)
166
167    def test_coreos_os_release(self):
168        desired_outcome = {
169            'id': 'coreos',
170            'name': 'CoreOS',
171            'pretty_name': 'CoreOS 899.15.0',
172            'version': '899.15.0',
173            'pretty_version': '899.15.0',
174            'best_version': '899.15.0'
175        }
176        self._test_outcome(desired_outcome)
177
178    def test_debian8_os_release(self):
179        desired_outcome = {
180            'id': 'debian',
181            'name': 'Debian GNU/Linux',
182            'pretty_name': 'Debian GNU/Linux 8 (jessie)',
183            'version': '8',
184            'pretty_version': '8 (jessie)',
185            'best_version': '8',
186            'codename': 'jessie'
187        }
188        self._test_outcome(desired_outcome)
189
190    def test_fedora19_os_release(self):
191        desired_outcome = {
192            'id': 'fedora',
193            'name': 'Fedora',
194            'pretty_name': u'Fedora 19 (Schr\u00F6dinger\u2019s Cat)',
195            'version': '19',
196            'pretty_version': u'19 (Schr\u00F6dinger\u2019s Cat)',
197            'best_version': '19',
198            'codename': u'Schr\u00F6dinger\u2019s Cat'
199        }
200        self._test_outcome(desired_outcome)
201
202    def test_fedora23_os_release(self):
203        desired_outcome = {
204            'id': 'fedora',
205            'name': 'Fedora',
206            'pretty_name': 'Fedora 23 (Twenty Three)',
207            'version': '23',
208            'pretty_version': '23 (Twenty Three)',
209            'best_version': '23',
210            'codename': 'Twenty Three'
211        }
212        self._test_outcome(desired_outcome)
213
214    def test_fedora30_os_release(self):
215        # Fedora 21 and above no longer have code names but the metadata in os-release was only
216        # changed in a detectable way in Fedora 30+.  The piece in parenthesis in the pretty_name
217        # field contains the VARIANT and differs depending on the variant which was installed.
218        desired_outcome = {
219            'id': 'fedora',
220            'name': 'Fedora',
221            'pretty_name': 'Fedora 30 (Thirty)',
222            'version': '30',
223            'pretty_version': '30',
224            'best_version': '30',
225            'codename': ''
226        }
227        self._test_outcome(desired_outcome)
228
229    def test_kvmibm1_os_release(self):
230        desired_outcome = {
231            'id': 'kvmibm',
232            'name': 'KVM for IBM z Systems',
233            'pretty_name': 'KVM for IBM z Systems 1.1.1 (Z)',
234            'version': '1.1.1',
235            'pretty_version': '1.1.1 (Z)',
236            'best_version': '1.1.1',
237            'like': 'rhel fedora',
238            'codename': 'Z'
239        }
240        self._test_outcome(desired_outcome)
241
242    def test_linuxmint17_os_release(self):
243        # Note: LinuxMint 17 actually *does* have Ubuntu 14.04 data in its
244        #       os-release file. See discussion in GitHub issue #78.
245        desired_outcome = {
246            'id': 'ubuntu',
247            'name': 'Ubuntu',
248            'pretty_name': 'Ubuntu 14.04.3 LTS',
249            'version': '14.04',
250            'pretty_version': '14.04 (Trusty Tahr)',
251            'best_version': '14.04.3',
252            'like': 'debian',
253            'codename': 'Trusty Tahr'
254        }
255        self._test_outcome(desired_outcome)
256
257    def test_mageia5_os_release(self):
258        desired_outcome = {
259            'id': 'mageia',
260            'name': 'Mageia',
261            'pretty_name': 'Mageia 5',
262            'version': '5',
263            'pretty_version': '5',
264            'best_version': '5',
265            'like': 'mandriva fedora',
266        }
267        self._test_outcome(desired_outcome)
268
269    def test_manjaro1512_os_release(self):
270        self._test_outcome({
271            'id': 'manjaro',
272            'name': 'Manjaro Linux',
273            'pretty_name': 'Manjaro Linux',
274        })
275
276    def test_opensuse42_os_release(self):
277        desired_outcome = {
278            'id': 'opensuse',
279            'name': 'openSUSE Leap',
280            'pretty_name': 'openSUSE Leap 42.1 (x86_64)',
281            'version': '42.1',
282            'pretty_version': '42.1',
283            'best_version': '42.1',
284            'like': 'suse',
285        }
286        self._test_outcome(desired_outcome)
287
288    def test_raspbian7_os_release(self):
289        desired_outcome = {
290            'id': 'raspbian',
291            'name': 'Raspbian GNU/Linux',
292            'pretty_name': 'Raspbian GNU/Linux 7 (wheezy)',
293            'version': '7',
294            'pretty_version': '7 (wheezy)',
295            'best_version': '7',
296            'like': 'debian',
297            'codename': 'wheezy'
298        }
299        self._test_outcome(desired_outcome)
300
301    def test_raspbian8_os_release(self):
302        desired_outcome = {
303            'id': 'raspbian',
304            'name': 'Raspbian GNU/Linux',
305            'pretty_name': 'Raspbian GNU/Linux 8 (jessie)',
306            'version': '8',
307            'pretty_version': '8 (jessie)',
308            'best_version': '8',
309            'like': 'debian',
310            'codename': 'jessie'
311        }
312        self._test_outcome(desired_outcome)
313
314    def test_rhel7_os_release(self):
315        desired_outcome = {
316            'id': 'rhel',
317            'name': 'Red Hat Enterprise Linux Server',
318            'pretty_name': 'Red Hat Enterprise Linux Server 7.0 (Maipo)',
319            'version': '7.0',
320            'pretty_version': '7.0 (Maipo)',
321            'best_version': '7.0',
322            'like': 'fedora',
323            'codename': 'Maipo'
324        }
325        self._test_outcome(desired_outcome)
326
327    def test_slackware14_os_release(self):
328        desired_outcome = {
329            'id': 'slackware',
330            'name': 'Slackware',
331            'pretty_name': 'Slackware 14.1',
332            'version': '14.1',
333            'pretty_version': '14.1',
334            'best_version': '14.1'
335        }
336        self._test_outcome(desired_outcome)
337
338    def test_sles12_os_release(self):
339        desired_outcome = {
340            'id': 'sles',
341            'name': 'SLES',
342            'pretty_name': 'SUSE Linux Enterprise Server 12 SP1',
343            'version': '12.1',
344            'pretty_version': '12.1',
345            'best_version': '12.1'
346        }
347        self._test_outcome(desired_outcome)
348
349    def test_ubuntu14_os_release(self):
350        desired_outcome = {
351            'id': 'ubuntu',
352            'name': 'Ubuntu',
353            'pretty_name': 'Ubuntu 14.04.3 LTS',
354            'version': '14.04',
355            'pretty_version': '14.04 (Trusty Tahr)',
356            'best_version': '14.04.3',
357            'like': 'debian',
358            'codename': 'Trusty Tahr'
359        }
360        self._test_outcome(desired_outcome)
361
362    def test_ubuntu16_os_release(self):
363        desired_outcome = {
364            'id': 'ubuntu',
365            'name': 'Ubuntu',
366            'pretty_name': 'Ubuntu 16.04.1 LTS',
367            'version': '16.04',
368            'pretty_version': '16.04 (xenial)',
369            'best_version': '16.04.1',
370            'like': 'debian',
371            'codename': 'xenial'
372        }
373        self._test_outcome(desired_outcome)
374
375    def test_amazon2016_os_release(self):
376        desired_outcome = {
377            'id': 'amzn',
378            'name': 'Amazon Linux AMI',
379            'pretty_name': 'Amazon Linux AMI 2016.03',
380            'version': '2016.03',
381            'pretty_version': '2016.03',
382            'best_version': '2016.03',
383            'like': 'rhel fedora'
384        }
385        self._test_outcome(desired_outcome)
386
387    def test_scientific7_os_release(self):
388        desired_outcome = {
389            'id': 'rhel',
390            'name': 'Scientific Linux',
391            'pretty_name': 'Scientific Linux 7.2 (Nitrogen)',
392            'version': '7.2',
393            'pretty_version': '7.2 (Nitrogen)',
394            'best_version': '7.2',
395            'like': 'fedora',
396            'codename': 'Nitrogen'
397        }
398        self._test_outcome(desired_outcome)
399
400    def test_gentoo_os_release(self):
401        desired_outcome = {
402            'id': 'gentoo',
403            'name': 'Gentoo',
404            'pretty_name': 'Gentoo/Linux',
405        }
406        self._test_outcome(desired_outcome)
407
408    def test_openelec6_os_release(self):
409        desired_outcome = {
410            'id': 'openelec',
411            'name': 'OpenELEC',
412            'pretty_name': 'OpenELEC (official) - Version: 6.0.3',
413            'version': '6.0',
414            'pretty_version': '6.0',
415            'best_version': '6.0.3',
416        }
417        self._test_outcome(desired_outcome)
418
419    def test_cloudlinux7_os_release(self):
420        desired_outcome = {
421            'id': 'cloudlinux',
422            'codename': 'Yury Malyshev',
423            'name': 'CloudLinux',
424            'pretty_name': 'CloudLinux 7.3 (Yury Malyshev)',
425            'like': 'rhel fedora centos',
426            'version': '7.3',
427            'pretty_version': '7.3 (Yury Malyshev)',
428            'best_version': '7.3',
429            'major_version': '7',
430            'minor_version': '3'
431        }
432        self._test_outcome(desired_outcome)
433
434
435@pytest.mark.skipif(not IS_LINUX, reason='Irrelevant on non-linux')
436class TestLSBRelease(DistroTestCase):
437
438    def setup_method(self, test_method):
439        super(TestLSBRelease, self).setup_method(test_method)
440        dist = test_method.__name__.split('_')[1]
441        self._setup_for_distro(os.path.join(DISTROS_DIR, dist))
442        self.distro = distro.LinuxDistribution(True, 'non', 'non')
443
444    def _test_outcome(self, outcome):
445        assert self.distro.id() == outcome.get('id', '')
446        assert self.distro.name() == outcome.get('name', '')
447        assert self.distro.name(pretty=True) == outcome.get('pretty_name', '')
448        assert self.distro.version() == outcome.get('version', '')
449        assert self.distro.version(pretty=True) == \
450            outcome.get('pretty_version', '')
451        assert self.distro.version(best=True) == \
452            outcome.get('best_version', '')
453        assert self.distro.like() == outcome.get('like', '')
454        assert self.distro.codename() == outcome.get('codename', '')
455
456    def test_linuxmint17_lsb_release(self):
457        desired_outcome = {
458            'id': 'linuxmint',
459            'name': 'LinuxMint',
460            'pretty_name': 'Linux Mint 17.3 Rosa',
461            'version': '17.3',
462            'pretty_version': '17.3 (rosa)',
463            'best_version': '17.3',
464            'codename': 'rosa'
465        }
466        self._test_outcome(desired_outcome)
467
468    def test_manjaro1512_lsb_release(self):
469        self._test_outcome({
470            'id': 'manjarolinux',
471            'name': 'ManjaroLinux',
472            'pretty_name': 'Manjaro Linux',
473            'version': '15.12',
474            'pretty_version': '15.12 (Capella)',
475            'best_version': '15.12',
476            'codename': 'Capella'
477        })
478
479    # @pytest.mark.xfail
480    # def test_openelec6_lsb_release(self):
481    #     # TODO: This should be fixed as part of #109 when dealing
482    #     # with distro inconsistencies
483    #     desired_outcome = {
484    #         'id': 'openelec',
485    #         'name': 'OpenELEC',
486    #         'pretty_name': 'OpenELEC (official) - Version: 6.0.3',
487    #         'version': '6.0.3',
488    #         'pretty_version': '6.0.3',
489    #         'best_version': '6.0.3',
490    #     }
491    #     self._test_outcome(desired_outcome)
492
493    def test_openbsd62_uname(self):
494        self._test_outcome({
495            'id': 'openbsd',
496            'name': 'OpenBSD',
497            'version': '6.2',
498            'pretty_name': 'OpenBSD 6.2',
499            'pretty_version': '6.2',
500            'best_version': '6.2'
501        })
502
503    def test_netbsd711_uname(self):
504        self._test_outcome({
505            'id': 'netbsd',
506            'name': 'NetBSD',
507            'version': '7.1.1',
508            'pretty_name': 'NetBSD 7.1.1',
509            'pretty_version': '7.1.1',
510            'best_version': '7.1.1'
511        })
512
513    def test_freebsd111_uname(self):
514        self._test_outcome({
515            'id': 'freebsd',
516            'name': 'FreeBSD',
517            'version': '11.1',
518            'pretty_name': 'FreeBSD 11.1',
519            'pretty_version': '11.1',
520            'best_version': '11.1'
521        })
522
523    def test_ubuntu14normal_lsb_release(self):
524        self._setup_for_distro(os.path.join(TESTDISTROS, 'lsb',
525                                            'ubuntu14_normal'))
526
527        self.distro = distro.LinuxDistribution(True, 'non', 'non')
528
529        desired_outcome = {
530            'id': 'ubuntu',
531            'name': 'Ubuntu',
532            'pretty_name': 'Ubuntu 14.04.3 LTS',
533            'version': '14.04',
534            'pretty_version': '14.04 (trusty)',
535            'best_version': '14.04.3',
536            'codename': 'trusty'
537        }
538        self._test_outcome(desired_outcome)
539
540    def test_ubuntu14nomodules_lsb_release(self):
541        self._setup_for_distro(os.path.join(TESTDISTROS, 'lsb',
542                                            'ubuntu14_nomodules'))
543
544        self.distro = distro.LinuxDistribution(True, 'non', 'non')
545
546        desired_outcome = {
547            'id': 'ubuntu',
548            'name': 'Ubuntu',
549            'pretty_name': 'Ubuntu 14.04.3 LTS',
550            'version': '14.04',
551            'pretty_version': '14.04 (trusty)',
552            'best_version': '14.04.3',
553            'codename': 'trusty'
554        }
555        self._test_outcome(desired_outcome)
556
557    def test_trailingblanks_lsb_release(self):
558        self._setup_for_distro(os.path.join(TESTDISTROS, 'lsb',
559                                            'ubuntu14_trailingblanks'))
560
561        self.distro = distro.LinuxDistribution(True, 'non', 'non')
562
563        desired_outcome = {
564            'id': 'ubuntu',
565            'name': 'Ubuntu',
566            'pretty_name': 'Ubuntu 14.04.3 LTS',
567            'version': '14.04',
568            'pretty_version': '14.04 (trusty)',
569            'best_version': '14.04.3',
570            'codename': 'trusty'
571        }
572        self._test_outcome(desired_outcome)
573
574    @pytest.mark.parametrize('errnum', ('001', '002', '126', '130', '255'))
575    def test_lsb_release_error_level(self, errnum):
576        self._setup_for_distro(os.path.join(
577            TESTDISTROS, 'lsb', 'lsb_rc{0}'.format(errnum)))
578        with pytest.raises(subprocess.CalledProcessError) as excinfo:
579            distro.LinuxDistribution(True, 'non', 'non')._lsb_release_info
580        assert excinfo.value.returncode == int(errnum)
581
582
583@pytest.mark.skipif(not IS_LINUX, reason='Irrelevant on non-linux')
584class TestSpecialRelease(DistroTestCase):
585    def _test_outcome(self, outcome):
586        assert self.distro.id() == outcome.get('id', '')
587        assert self.distro.name() == outcome.get('name', '')
588        assert self.distro.name(pretty=True) == outcome.get('pretty_name', '')
589        assert self.distro.version() == outcome.get('version', '')
590        assert self.distro.version(pretty=True) == \
591            outcome.get('pretty_version', '')
592        assert self.distro.version(best=True) == \
593            outcome.get('best_version', '')
594        assert self.distro.like() == outcome.get('like', '')
595        assert self.distro.codename() == outcome.get('codename', '')
596        assert self.distro.major_version() == outcome.get('major_version', '')
597        assert self.distro.minor_version() == outcome.get('minor_version', '')
598        assert self.distro.build_number() == outcome.get('build_number', '')
599
600    def test_empty_release(self):
601        distro_release = os.path.join(SPECIAL, 'empty-release')
602        self.distro = distro.LinuxDistribution(False, 'non', distro_release)
603
604        desired_outcome = {
605            'id': 'empty'
606        }
607        self._test_outcome(desired_outcome)
608
609    def test_unknowndistro_release(self):
610        self._setup_for_distro(os.path.join(TESTDISTROS, 'distro',
611                                            'unknowndistro'))
612
613        self.distro = distro.LinuxDistribution()
614
615        desired_outcome = {
616            'id': 'unknowndistro',
617            'name': 'Unknown Distro',
618            'pretty_name': 'Unknown Distro 1.0 (Unknown Codename)',
619            'version': '1.0',
620            'pretty_version': '1.0 (Unknown Codename)',
621            'best_version': '1.0',
622            'codename': 'Unknown Codename',
623            'major_version': '1',
624            'minor_version': '0'
625        }
626        self._test_outcome(desired_outcome)
627
628    def test_bad_uname(self):
629        self._setup_for_distro(os.path.join(TESTDISTROS, 'distro',
630                                            'baduname'))
631        self.distro = distro.LinuxDistribution()
632
633        assert self.distro.uname_attr('id') == ''
634        assert self.distro.uname_attr('name') == ''
635        assert self.distro.uname_attr('release') == ''
636
637
638@pytest.mark.skipif(not IS_LINUX, reason='Irrelevant on non-linux')
639class TestDistroRelease:
640
641    def _test_outcome(self,
642                      outcome,
643                      distro_name='',
644                      version='',
645                      release_file_id='',
646                      release_file_suffix='release'):
647        release_file_id = release_file_id or distro_name
648        distro_release = os.path.join(
649            DISTROS_DIR, distro_name + version, 'etc', '{0}-{1}'.format(
650                release_file_id, release_file_suffix))
651        self.distro = distro.LinuxDistribution(False, 'non', distro_release)
652
653        assert self.distro.id() == outcome.get('id', '')
654        assert self.distro.name() == outcome.get('name', '')
655        assert self.distro.name(pretty=True) == outcome.get('pretty_name', '')
656        assert self.distro.version() == outcome.get('version', '')
657        assert self.distro.version(pretty=True) == \
658            outcome.get('pretty_version', '')
659        assert self.distro.version(best=True) == \
660            outcome.get('best_version', '')
661        assert self.distro.like() == outcome.get('like', '')
662        assert self.distro.codename() == outcome.get('codename', '')
663        assert self.distro.major_version() == outcome.get('major_version', '')
664        assert self.distro.minor_version() == outcome.get('minor_version', '')
665        assert self.distro.build_number() == outcome.get('build_number', '')
666
667    def test_arch_dist_release(self):
668        desired_outcome = {
669            'id': 'arch'
670        }
671        self._test_outcome(desired_outcome, 'arch')
672
673    def test_centos5_dist_release(self):
674        desired_outcome = {
675            'id': 'centos',
676            'name': 'CentOS',
677            'pretty_name': 'CentOS 5.11 (Final)',
678            'version': '5.11',
679            'pretty_version': '5.11 (Final)',
680            'best_version': '5.11',
681            'codename': 'Final',
682            'major_version': '5',
683            'minor_version': '11'
684        }
685        self._test_outcome(desired_outcome, 'centos', '5')
686
687    def test_centos7_dist_release(self):
688        desired_outcome = {
689            'id': 'centos',
690            'name': 'CentOS Linux',
691            'pretty_name': 'CentOS Linux 7.1.1503 (Core)',
692            'version': '7.1.1503',
693            'pretty_version': '7.1.1503 (Core)',
694            'best_version': '7.1.1503',
695            'codename': 'Core',
696            'major_version': '7',
697            'minor_version': '1',
698            'build_number': '1503'
699        }
700        self._test_outcome(desired_outcome, 'centos', '7')
701
702    def test_fedora19_dist_release(self):
703        desired_outcome = {
704            'id': 'fedora',
705            'name': 'Fedora',
706            'pretty_name': u'Fedora 19 (Schr\u00F6dinger\u2019s Cat)',
707            'version': '19',
708            'pretty_version': u'19 (Schr\u00F6dinger\u2019s Cat)',
709            'best_version': '19',
710            'codename': u'Schr\u00F6dinger\u2019s Cat',
711            'major_version': '19'
712        }
713        self._test_outcome(desired_outcome, 'fedora', '19')
714
715    def test_fedora23_dist_release(self):
716        desired_outcome = {
717            'id': 'fedora',
718            'name': 'Fedora',
719            'pretty_name': 'Fedora 23 (Twenty Three)',
720            'version': '23',
721            'pretty_version': '23 (Twenty Three)',
722            'best_version': '23',
723            'codename': 'Twenty Three',
724            'major_version': '23'
725        }
726        self._test_outcome(desired_outcome, 'fedora', '23')
727
728    def test_fedora30_dist_release(self):
729        desired_outcome = {
730            'id': 'fedora',
731            'name': 'Fedora',
732            'pretty_name': 'Fedora 30 (Thirty)',
733            'version': '30',
734            'pretty_version': '30 (Thirty)',
735            'best_version': '30',
736            'codename': 'Thirty',
737            'major_version': '30'
738        }
739        self._test_outcome(desired_outcome, 'fedora', '30')
740
741    def test_gentoo_dist_release(self):
742        desired_outcome = {
743            'id': 'gentoo',
744            'name': 'Gentoo Base System',
745            'pretty_name': 'Gentoo Base System 2.2',
746            'version': '2.2',
747            'pretty_version': '2.2',
748            'best_version': '2.2',
749            'major_version': '2',
750            'minor_version': '2',
751        }
752        self._test_outcome(desired_outcome, 'gentoo')
753
754    def test_kvmibm1_dist_release(self):
755        desired_outcome = {
756            'id': 'base',
757            'name': 'KVM for IBM z Systems',
758            'pretty_name': 'KVM for IBM z Systems 1.1.1 (Z)',
759            'version': '1.1.1',
760            'pretty_version': '1.1.1 (Z)',
761            'best_version': '1.1.1',
762            'codename': 'Z',
763            'major_version': '1',
764            'minor_version': '1',
765            'build_number': '1'
766        }
767        self._test_outcome(desired_outcome, 'kvmibm', '1', 'base')
768
769    def test_mageia5_dist_release(self):
770        desired_outcome = {
771            'id': 'mageia',
772            'name': 'Mageia',
773            'pretty_name': 'Mageia 5 (Official)',
774            'version': '5',
775            'pretty_version': '5 (Official)',
776            'best_version': '5',
777            'codename': 'Official',
778            'major_version': '5'
779        }
780        self._test_outcome(desired_outcome, 'mageia', '5')
781
782    def test_manjaro1512_dist_release(self):
783        self._test_outcome({
784            'id': 'manjaro',
785            'name': 'Manjaro Linux',
786            'pretty_name': 'Manjaro Linux',
787            'version': '',
788            'codename': ''
789        }, 'manjaro', '1512')
790
791    def test_opensuse42_dist_release(self):
792        desired_outcome = {
793            'id': 'suse',
794            'name': 'openSUSE',
795            'pretty_name': 'openSUSE 42.1 (x86_64)',
796            'version': '42.1',
797            'pretty_version': '42.1 (x86_64)',
798            'best_version': '42.1',
799            'codename': 'x86_64',
800            'major_version': '42',
801            'minor_version': '1'
802        }
803        self._test_outcome(desired_outcome, 'opensuse', '42', 'SuSE')
804
805    def test_oracle7_dist_release(self):
806        desired_outcome = {
807            'id': 'oracle',
808            'name': 'Oracle Linux Server',
809            'pretty_name': 'Oracle Linux Server 7.5',
810            'version': '7.5',
811            'pretty_version': '7.5',
812            'best_version': '7.5',
813            'major_version': '7',
814            'minor_version': '5'
815        }
816        self._test_outcome(desired_outcome, 'oracle', '7')
817
818    def test_rhel6_dist_release(self):
819        desired_outcome = {
820            'id': 'rhel',
821            'name': 'Red Hat Enterprise Linux Server',
822            'pretty_name': 'Red Hat Enterprise Linux Server 6.5 (Santiago)',
823            'version': '6.5',
824            'pretty_version': '6.5 (Santiago)',
825            'best_version': '6.5',
826            'codename': 'Santiago',
827            'major_version': '6',
828            'minor_version': '5'
829        }
830        self._test_outcome(desired_outcome, 'rhel', '6', 'redhat')
831
832    def test_rhel7_dist_release(self):
833        desired_outcome = {
834            'id': 'rhel',
835            'name': 'Red Hat Enterprise Linux Server',
836            'pretty_name': 'Red Hat Enterprise Linux Server 7.0 (Maipo)',
837            'version': '7.0',
838            'pretty_version': '7.0 (Maipo)',
839            'best_version': '7.0',
840            'codename': 'Maipo',
841            'major_version': '7',
842            'minor_version': '0'
843        }
844        self._test_outcome(desired_outcome, 'rhel', '7', 'redhat')
845
846    def test_slackware14_dist_release(self):
847        desired_outcome = {
848            'id': 'slackware',
849            'name': 'Slackware',
850            'pretty_name': 'Slackware 14.1',
851            'version': '14.1',
852            'pretty_version': '14.1',
853            'best_version': '14.1',
854            'major_version': '14',
855            'minor_version': '1'
856        }
857        self._test_outcome(
858            desired_outcome,
859            'slackware',
860            '14',
861            release_file_suffix='version')
862
863    def test_sles12_dist_release(self):
864        desired_outcome = {
865            'id': 'suse',
866            'name': 'SUSE Linux Enterprise Server',
867            'pretty_name': 'SUSE Linux Enterprise Server 12 (s390x)',
868            'version': '12',
869            'pretty_version': '12 (s390x)',
870            'best_version': '12',
871            'major_version': '12',
872            'codename': 's390x'
873        }
874        self._test_outcome(desired_outcome, 'sles', '12', 'SuSE')
875
876    def test_cloudlinux5_dist_release(self):
877        # Uses redhat-release only to get information.
878        # The id of 'rhel' can only be fixed with issue #109.
879        desired_outcome = {
880            'id': 'cloudlinux',
881            'codename': 'Vladislav Volkov',
882            'name': 'CloudLinux Server',
883            'pretty_name': 'CloudLinux Server 5.11 (Vladislav Volkov)',
884            'version': '5.11',
885            'pretty_version': '5.11 (Vladislav Volkov)',
886            'best_version': '5.11',
887            'major_version': '5',
888            'minor_version': '11'
889        }
890        self._test_outcome(desired_outcome, 'cloudlinux', '5', 'redhat')
891
892    def test_cloudlinux6_dist_release(self):
893        # Same as above, only has redhat-release.
894        desired_outcome = {
895            'id': 'cloudlinux',
896            'codename': 'Oleg Makarov',
897            'name': 'CloudLinux Server',
898            'pretty_name': 'CloudLinux Server 6.8 (Oleg Makarov)',
899            'version': '6.8',
900            'pretty_version': '6.8 (Oleg Makarov)',
901            'best_version': '6.8',
902            'major_version': '6',
903            'minor_version': '8'
904        }
905        self._test_outcome(desired_outcome, 'cloudlinux', '6', 'redhat')
906
907    def test_cloudlinux7_dist_release(self):
908        desired_outcome = {
909            'id': 'cloudlinux',
910            'codename': 'Yury Malyshev',
911            'name': 'CloudLinux',
912            'pretty_name': 'CloudLinux 7.3 (Yury Malyshev)',
913            'version': '7.3',
914            'pretty_version': '7.3 (Yury Malyshev)',
915            'best_version': '7.3',
916            'major_version': '7',
917            'minor_version': '3'
918        }
919        self._test_outcome(desired_outcome, 'cloudlinux', '7', 'redhat')
920
921
922@pytest.mark.skipif(not IS_LINUX, reason='Irrelevant on non-linux')
923class TestOverall(DistroTestCase):
924    """Test a LinuxDistribution object created with default arguments.
925
926    The direct accessor functions on that object are tested (e.g. `id()`); they
927    implement the precedence between the different sources of information.
928
929    In addition, because the distro release file is searched when not
930    specified, the information resulting from the distro release file is also
931    tested. The LSB and os-release sources are not tested again, because their
932    test is already done in TestLSBRelease and TestOSRelease, and their
933    algorithm does not depend on whether or not the file is specified.
934
935    TODO: This class should have testcases for all distros that are claimed
936    to be reliably maintained w.r.t. to their ID (see `id()`). Testcases for
937    the following distros are still missing:
938      * `amazon` - Amazon Linux
939      * `gentoo` - GenToo Linux
940      * `ibm_powerkvm` - IBM PowerKVM
941      * `parallels` - Parallels
942      * `pidora` - Pidora (Fedora remix for Raspberry Pi)
943      * `raspbian` - Raspbian
944      * `scientific` - Scientific Linux
945      * `xenserver` - XenServer
946    """
947
948    def setup_method(self, test_method):
949        super(TestOverall, self).setup_method(test_method)
950        dist = test_method.__name__.split('_')[1]
951        self._setup_for_distro(os.path.join(DISTROS_DIR, dist))
952        self.distro = distro.LinuxDistribution()
953
954    def _test_outcome(self, outcome):
955        assert self.distro.id() == outcome.get('id', '')
956        assert self.distro.name() == outcome.get('name', '')
957        assert self.distro.name(pretty=True) == outcome.get('pretty_name', '')
958        assert self.distro.version() == outcome.get('version', '')
959        assert self.distro.version(pretty=True) == \
960            outcome.get('pretty_version', '')
961        assert self.distro.version(best=True) == \
962            outcome.get('best_version', '')
963        assert self.distro.like() == outcome.get('like', '')
964        assert self.distro.codename() == outcome.get('codename', '')
965        assert self.distro.major_version() == outcome.get('major_version', '')
966        assert self.distro.minor_version() == outcome.get('minor_version', '')
967        assert self.distro.build_number() == outcome.get('build_number', '')
968
969    def _test_non_existing_release_file(self):
970        # Test the info from the searched distro release file
971        # does not have one.
972        assert self.distro.distro_release_file == ''
973        assert len(self.distro.distro_release_info()) == 0
974
975    def _test_release_file_info(self, filename, outcome):
976        # Test the info from the searched distro release file
977        assert os.path.basename(self.distro.distro_release_file) == filename
978        distro_info = self.distro.distro_release_info()
979        for key, value in outcome.items():
980            assert distro_info[key] == value
981        return distro_info
982
983    def test_arch_release(self):
984        desired_outcome = {
985            'id': 'arch',
986            'name': 'Arch Linux',
987            'pretty_name': 'Arch Linux',
988        }
989        self._test_outcome(desired_outcome)
990
991        # Test the info from the searched distro release file
992        # Does not have one; The empty /etc/arch-release file is not
993        # considered a valid distro release file:
994        self._test_non_existing_release_file()
995
996    def test_centos5_release(self):
997        desired_outcome = {
998            'id': 'centos',
999            'name': 'CentOS',
1000            'pretty_name': 'CentOS 5.11 (Final)',
1001            'version': '5.11',
1002            'pretty_version': '5.11 (Final)',
1003            'best_version': '5.11',
1004            'codename': 'Final',
1005            'major_version': '5',
1006            'minor_version': '11'
1007        }
1008        self._test_outcome(desired_outcome)
1009
1010        desired_info = {
1011            'id': 'centos',
1012            'name': 'CentOS',
1013            'version_id': '5.11',
1014            'codename': 'Final'
1015        }
1016        self._test_release_file_info('centos-release', desired_info)
1017
1018    def test_centos7_release(self):
1019        desired_outcome = {
1020            'id': 'centos',
1021            'name': 'CentOS Linux',
1022            'pretty_name': 'CentOS Linux 7 (Core)',
1023            'version': '7',
1024            'pretty_version': '7 (Core)',
1025            'best_version': '7.1.1503',
1026            'like': 'rhel fedora',
1027            'codename': 'Core',
1028            'major_version': '7'
1029        }
1030        self._test_outcome(desired_outcome)
1031
1032        desired_info = {
1033            'id': 'centos',
1034            'name': 'CentOS Linux',
1035            'version_id': '7.1.1503',
1036            'codename': 'Core'
1037        }
1038        self._test_release_file_info('centos-release', desired_info)
1039
1040    def test_coreos_release(self):
1041        desired_outcome = {
1042            'id': 'coreos',
1043            'name': 'CoreOS',
1044            'pretty_name': 'CoreOS 899.15.0',
1045            'version': '899.15.0',
1046            'pretty_version': '899.15.0',
1047            'best_version': '899.15.0',
1048            'major_version': '899',
1049            'minor_version': '15',
1050            'build_number': '0'
1051        }
1052        self._test_outcome(desired_outcome)
1053        self._test_non_existing_release_file()
1054
1055    def test_debian8_release(self):
1056        desired_outcome = {
1057            'id': 'debian',
1058            'name': 'Debian GNU/Linux',
1059            'pretty_name': 'Debian GNU/Linux 8 (jessie)',
1060            'version': '8',
1061            'pretty_version': '8 (jessie)',
1062            'best_version': '8.2',
1063            'codename': 'jessie',
1064            'major_version': '8'
1065        }
1066        self._test_outcome(desired_outcome)
1067        self._test_non_existing_release_file()
1068
1069    def test_exherbo_release(self):
1070        desired_outcome = {
1071            'id': 'exherbo',
1072            'name': 'Exherbo',
1073            'pretty_name': 'Exherbo Linux',
1074        }
1075        self._test_outcome(desired_outcome)
1076
1077    def test_fedora19_release(self):
1078        desired_outcome = {
1079            'id': 'fedora',
1080            'name': 'Fedora',
1081            'pretty_name': u'Fedora 19 (Schr\u00F6dinger\u2019s Cat)',
1082            'version': '19',
1083            'pretty_version': u'19 (Schr\u00F6dinger\u2019s Cat)',
1084            'best_version': '19',
1085            'codename': u'Schr\u00F6dinger\u2019s Cat',
1086            'major_version': '19'
1087        }
1088        self._test_outcome(desired_outcome)
1089
1090        desired_info = {
1091            'id': 'fedora',
1092            'name': 'Fedora',
1093            'version_id': '19',
1094            'codename': u'Schr\u00F6dinger\u2019s Cat'
1095        }
1096        self._test_release_file_info('fedora-release', desired_info)
1097
1098    def test_fedora23_release(self):
1099        desired_outcome = {
1100            'id': 'fedora',
1101            'name': 'Fedora',
1102            'pretty_name': 'Fedora 23 (Twenty Three)',
1103            'version': '23',
1104            'pretty_version': '23 (Twenty Three)',
1105            'best_version': '23',
1106            'codename': 'Twenty Three',
1107            'major_version': '23'
1108        }
1109        self._test_outcome(desired_outcome)
1110
1111        desired_info = {
1112            'id': 'fedora',
1113            'name': 'Fedora',
1114            'version_id': '23',
1115            'codename': 'Twenty Three'
1116        }
1117        self._test_release_file_info('fedora-release', desired_info)
1118
1119    def test_fedora30_release(self):
1120        desired_outcome = {
1121            'id': 'fedora',
1122            'name': 'Fedora',
1123            'pretty_name': 'Fedora 30 (Thirty)',
1124            'version': '30',
1125            'pretty_version': '30',
1126            'best_version': '30',
1127            'codename': '',
1128            'major_version': '30'
1129        }
1130        self._test_outcome(desired_outcome)
1131
1132        desired_info = {
1133            'id': 'fedora',
1134            'name': 'Fedora',
1135            'version_id': '30',
1136            'codename': 'Thirty'
1137        }
1138        self._test_release_file_info('fedora-release', desired_info)
1139
1140    def test_kvmibm1_release(self):
1141        desired_outcome = {
1142            'id': 'kvmibm',
1143            'name': 'KVM for IBM z Systems',
1144            'pretty_name': 'KVM for IBM z Systems 1.1.1 (Z)',
1145            'version': '1.1.1',
1146            'pretty_version': '1.1.1 (Z)',
1147            'best_version': '1.1.1',
1148            'like': 'rhel fedora',
1149            'codename': 'Z',
1150            'major_version': '1',
1151            'minor_version': '1',
1152            'build_number': '1'
1153        }
1154        self._test_outcome(desired_outcome)
1155
1156        desired_info = {
1157            'id': 'base',
1158            'name': 'KVM for IBM z Systems',
1159            'version_id': '1.1.1',
1160            'codename': 'Z'
1161        }
1162        self._test_release_file_info('base-release', desired_info)
1163
1164    def test_linuxmint17_release(self):
1165        desired_outcome = {
1166            'id': 'ubuntu',
1167            'name': 'Ubuntu',
1168            'pretty_name': 'Ubuntu 14.04.3 LTS',
1169            'version': '14.04',
1170            'pretty_version': '14.04 (Trusty Tahr)',
1171            'best_version': '14.04.3',
1172            'like': 'debian',
1173            'codename': 'Trusty Tahr',
1174            'major_version': '14',
1175            'minor_version': '04'
1176        }
1177        self._test_outcome(desired_outcome)
1178        self._test_non_existing_release_file()
1179
1180    def test_mageia5_release(self):
1181        desired_outcome = {
1182            'id': 'mageia',
1183            'name': 'Mageia',
1184            'pretty_name': 'Mageia 5',
1185            'version': '5',
1186            'pretty_version': '5 (thornicroft)',
1187            'best_version': '5',
1188            'like': 'mandriva fedora',
1189            # TODO: Codename differs between distro release and lsb_release.
1190            'codename': 'thornicroft',
1191            'major_version': '5'
1192        }
1193        self._test_outcome(desired_outcome)
1194
1195        desired_info = {
1196            'id': 'mageia',
1197            'name': 'Mageia',
1198            'version_id': '5',
1199            'codename': 'Official'
1200        }
1201        self._test_release_file_info('mageia-release', desired_info)
1202
1203    def test_manjaro1512_release(self):
1204        self._test_outcome({
1205            'id': 'manjaro',
1206            'name': 'Manjaro Linux',
1207            'pretty_name': 'Manjaro Linux',
1208            'version': '15.12',
1209            'pretty_version': '15.12 (Capella)',
1210            'best_version': '15.12',
1211            'major_version': '15',
1212            'minor_version': '12',
1213            'codename': 'Capella'
1214        })
1215
1216        self._test_release_file_info(
1217            'manjaro-release',
1218            {'id': 'manjaro',
1219             'name': 'Manjaro Linux'})
1220
1221    def test_opensuse42_release(self):
1222        desired_outcome = {
1223            'id': 'opensuse',
1224            'name': 'openSUSE Leap',
1225            'pretty_name': 'openSUSE Leap 42.1 (x86_64)',
1226            'version': '42.1',
1227            'pretty_version': '42.1 (x86_64)',
1228            'best_version': '42.1',
1229            'like': 'suse',
1230            'codename': 'x86_64',
1231            'major_version': '42',
1232            'minor_version': '1'
1233        }
1234        self._test_outcome(desired_outcome)
1235
1236        desired_info = {
1237            'id': 'SuSE',
1238            'name': 'openSUSE',
1239            'version_id': '42.1',
1240            'codename': 'x86_64'
1241        }
1242        self._test_release_file_info('SuSE-release', desired_info)
1243
1244    def test_oracle7_release(self):
1245        desired_outcome = {
1246            'id': 'oracle',
1247            'name': 'Oracle Linux Server',
1248            'pretty_name': 'Oracle Linux Server 7.5',
1249            'version': '7.5',
1250            'pretty_version': '7.5',
1251            'best_version': '7.5',
1252            'major_version': '7',
1253            'minor_version': '5'
1254        }
1255        self._test_outcome(desired_outcome)
1256
1257        desired_info = {
1258            'id': 'oracle',
1259            'name': 'Oracle Linux Server',
1260            'version_id': '7.5',
1261        }
1262        distro_info = self._test_release_file_info(
1263            'oracle-release', desired_info)
1264        assert 'codename' not in distro_info
1265
1266    def test_raspbian7_release(self):
1267        desired_outcome = {
1268            'id': 'raspbian',
1269            'name': 'Raspbian GNU/Linux',
1270            'pretty_name': 'Raspbian GNU/Linux 7 (wheezy)',
1271            'version': '7',
1272            'pretty_version': '7 (wheezy)',
1273            'best_version': '7',
1274            'like': 'debian',
1275            'codename': 'wheezy',
1276            'major_version': '7',
1277        }
1278        self._test_outcome(desired_outcome)
1279        self._test_non_existing_release_file()
1280
1281    def test_raspbian8_release(self):
1282        desired_outcome = {
1283            'id': 'raspbian',
1284            'name': 'Raspbian GNU/Linux',
1285            'pretty_name': 'Raspbian GNU/Linux 8 (jessie)',
1286            'version': '8',
1287            'pretty_version': '8 (jessie)',
1288            'best_version': '8',
1289            'like': 'debian',
1290            'codename': 'jessie',
1291            'major_version': '8',
1292        }
1293        self._test_outcome(desired_outcome)
1294        self._test_non_existing_release_file()
1295
1296    def test_rhel5_release(self):
1297        desired_outcome = {
1298            'id': 'rhel',
1299            'name': 'Red Hat Enterprise Linux Server',
1300            'pretty_name': 'Red Hat Enterprise Linux Server 5.11 (Tikanga)',
1301            'version': '5.11',
1302            'pretty_version': '5.11 (Tikanga)',
1303            'best_version': '5.11',
1304            'codename': 'Tikanga',
1305            'major_version': '5',
1306            'minor_version': '11'
1307        }
1308        self._test_outcome(desired_outcome)
1309
1310        desired_info = {
1311            'id': 'redhat',
1312            'name': 'Red Hat Enterprise Linux Server',
1313            'version_id': '5.11',
1314            'codename': 'Tikanga'
1315        }
1316        self._test_release_file_info('redhat-release', desired_info)
1317
1318    def test_rhel6_release(self):
1319        desired_outcome = {
1320            'id': 'rhel',
1321            'name': 'Red Hat Enterprise Linux Server',
1322            'pretty_name': 'Red Hat Enterprise Linux Server 6.5 (Santiago)',
1323            'version': '6.5',
1324            'pretty_version': '6.5 (Santiago)',
1325            'best_version': '6.5',
1326            'codename': 'Santiago',
1327            'major_version': '6',
1328            'minor_version': '5'
1329        }
1330        self._test_outcome(desired_outcome)
1331
1332        desired_info = {
1333            'id': 'redhat',
1334            'name': 'Red Hat Enterprise Linux Server',
1335            'version_id': '6.5',
1336            'codename': 'Santiago'
1337        }
1338        self._test_release_file_info('redhat-release', desired_info)
1339
1340    def test_rhel7_release(self):
1341        desired_outcome = {
1342            'id': 'rhel',
1343            'name': 'Red Hat Enterprise Linux Server',
1344            'pretty_name': 'Red Hat Enterprise Linux Server 7.0 (Maipo)',
1345            'version': '7.0',
1346            'pretty_version': '7.0 (Maipo)',
1347            'best_version': '7.0',
1348            'like': 'fedora',
1349            'codename': 'Maipo',
1350            'major_version': '7',
1351            'minor_version': '0'
1352        }
1353        self._test_outcome(desired_outcome)
1354
1355        desired_info = {
1356            'id': 'redhat',
1357            'name': 'Red Hat Enterprise Linux Server',
1358            'version_id': '7.0',
1359            'codename': 'Maipo'
1360        }
1361        self._test_release_file_info('redhat-release', desired_info)
1362
1363    def test_slackware14_release(self):
1364        desired_outcome = {
1365            'id': 'slackware',
1366            'name': 'Slackware',
1367            'pretty_name': 'Slackware 14.1',
1368            'version': '14.1',
1369            'pretty_version': '14.1',
1370            'best_version': '14.1',
1371            'major_version': '14',
1372            'minor_version': '1'
1373        }
1374        self._test_outcome(desired_outcome)
1375
1376        desired_info = {
1377            'id': 'slackware',
1378            'name': 'Slackware',
1379            'version_id': '14.1',
1380        }
1381        distro_info = self._test_release_file_info(
1382            'slackware-version', desired_info)
1383        assert 'codename' not in distro_info
1384
1385    def test_sles12_release(self):
1386        desired_outcome = {
1387            'id': 'sles',
1388            'name': 'SLES',
1389            'pretty_name': 'SUSE Linux Enterprise Server 12 SP1',
1390            'version': '12.1',
1391            'pretty_version': '12.1 (n/a)',
1392            'best_version': '12.1',
1393            'codename': 'n/a',
1394            'major_version': '12',
1395            'minor_version': '1'
1396        }
1397        self._test_outcome(desired_outcome)
1398
1399        desired_info = {
1400            'id': 'SuSE',
1401            'name': 'SUSE Linux Enterprise Server',
1402            'version_id': '12',
1403            'codename': 's390x'
1404        }
1405        self._test_release_file_info('SuSE-release', desired_info)
1406
1407    def test_ubuntu14_release(self):
1408        desired_outcome = {
1409            'id': 'ubuntu',
1410            'name': 'Ubuntu',
1411            'pretty_name': 'Ubuntu 14.04.3 LTS',
1412            'version': '14.04',
1413            'pretty_version': '14.04 (Trusty Tahr)',
1414            'best_version': '14.04.3',
1415            'like': 'debian',
1416            'codename': 'Trusty Tahr',
1417            'major_version': '14',
1418            'minor_version': '04'
1419        }
1420        self._test_outcome(desired_outcome)
1421
1422        # Test the info from the searched distro release file
1423        # Does not have one; /etc/debian_version is not considered a distro
1424        # release file:
1425        self._test_non_existing_release_file()
1426
1427    def test_ubuntu16_release(self):
1428        desired_outcome = {
1429            'id': 'ubuntu',
1430            'name': 'Ubuntu',
1431            'pretty_name': 'Ubuntu 16.04.1 LTS',
1432            'version': '16.04',
1433            'pretty_version': '16.04 (xenial)',
1434            'best_version': '16.04.1',
1435            'like': 'debian',
1436            'codename': 'xenial',
1437            'major_version': '16',
1438            'minor_version': '04'
1439        }
1440        self._test_outcome(desired_outcome)
1441
1442        # Test the info from the searched distro release file
1443        # Does not have one; /etc/debian_version is not considered a distro
1444        # release file:
1445        self._test_non_existing_release_file()
1446
1447    def test_amazon2016_release(self):
1448        desired_outcome = {
1449            'id': 'amzn',
1450            'name': 'Amazon Linux AMI',
1451            'pretty_name': 'Amazon Linux AMI 2016.03',
1452            'version': '2016.03',
1453            'pretty_version': '2016.03',
1454            'best_version': '2016.03',
1455            'like': 'rhel fedora',
1456            'major_version': '2016',
1457            'minor_version': '03'
1458        }
1459        self._test_outcome(desired_outcome)
1460
1461    def test_amazon2014_release(self):
1462        # Amazon Linux 2014 only contains a system-release file.
1463        # distro doesn't currently handle it.
1464        desired_outcome = {}
1465        self._test_outcome(desired_outcome)
1466
1467    def test_scientific6_release(self):
1468        desired_outcome = {
1469            'id': 'rhel',
1470            'name': 'Scientific Linux',
1471            'pretty_name': 'Scientific Linux 6.4 (Carbon)',
1472            'version': '6.4',
1473            'pretty_version': '6.4 (Carbon)',
1474            'best_version': '6.4',
1475            'codename': 'Carbon',
1476            'major_version': '6',
1477            'minor_version': '4',
1478
1479        }
1480        self._test_outcome(desired_outcome)
1481
1482        desired_info = {
1483            'id': 'redhat',
1484            'name': 'Scientific Linux',
1485            'version_id': '6.4',
1486            'codename': 'Carbon'
1487        }
1488        self._test_release_file_info('redhat-release', desired_info)
1489
1490    def test_scientific7_release(self):
1491        desired_outcome = {
1492            'id': 'rhel',
1493            'name': 'Scientific Linux',
1494            'pretty_name': 'Scientific Linux 7.2 (Nitrogen)',
1495            'version': '7.2',
1496            'pretty_version': '7.2 (Nitrogen)',
1497            'best_version': '7.2',
1498            'like': 'fedora',
1499            'codename': 'Nitrogen',
1500            'major_version': '7',
1501            'minor_version': '2',
1502        }
1503        self._test_outcome(desired_outcome)
1504
1505        desired_info = {
1506            'id': 'redhat',
1507            'name': 'Scientific Linux',
1508            'version_id': '7.2',
1509            'codename': 'Nitrogen'
1510        }
1511        self._test_release_file_info('redhat-release', desired_info)
1512
1513    def test_gentoo_release(self):
1514        desired_outcome = {
1515            'id': 'gentoo',
1516            'name': 'Gentoo',
1517            'pretty_name': 'Gentoo/Linux',
1518            'version': '2.2',
1519            'pretty_version': '2.2',
1520            'best_version': '2.2',
1521            'major_version': '2',
1522            'minor_version': '2',
1523        }
1524        self._test_outcome(desired_outcome)
1525
1526        desired_info = {
1527            'id': 'gentoo',
1528            'name': 'Gentoo Base System',
1529            'version_id': '2.2',
1530        }
1531        self._test_release_file_info('gentoo-release', desired_info)
1532
1533    def test_openelec6_release(self):
1534        desired_outcome = {
1535            'id': 'openelec',
1536            'name': 'OpenELEC',
1537            'pretty_name': 'OpenELEC (official) - Version: 6.0.3',
1538            'version': '6.0',
1539            'pretty_version': '6.0',
1540            'best_version': '6.0.3',
1541            'major_version': '6',
1542            'minor_version': '0',
1543        }
1544        self._test_outcome(desired_outcome)
1545
1546    def test_mandriva2011_release(self):
1547        desired_outcome = {
1548            'id': 'mandrivalinux',
1549            'name': 'MandrivaLinux',
1550            'pretty_name': 'Mandriva Linux 2011.0',
1551            'version': '2011.0',
1552            'pretty_version': '2011.0 (turtle)',
1553            'best_version': '2011.0',
1554            'major_version': '2011',
1555            'minor_version': '0',
1556            'codename': 'turtle'
1557        }
1558        self._test_outcome(desired_outcome)
1559
1560        desired_info = {
1561            'id': 'mandrake',
1562            'name': 'Mandriva Linux',
1563            'version_id': '2011.0',
1564        }
1565        self._test_release_file_info('mandrake-release', desired_info)
1566
1567    def test_cloudlinux5_release(self):
1568        # Uses redhat-release only to get information.
1569        # The id of 'rhel' can only be fixed with issue #109.
1570        desired_outcome = {
1571            'id': 'cloudlinux',
1572            'codename': 'Vladislav Volkov',
1573            'name': 'CloudLinux Server',
1574            'pretty_name': 'CloudLinux Server 5.11 (Vladislav Volkov)',
1575            'version': '5.11',
1576            'pretty_version': '5.11 (Vladislav Volkov)',
1577            'best_version': '5.11',
1578            'major_version': '5',
1579            'minor_version': '11'
1580        }
1581        self._test_outcome(desired_outcome)
1582
1583    def test_cloudlinux6_release(self):
1584        # Same as above, only has redhat-release.
1585        desired_outcome = {
1586            'id': 'cloudlinux',
1587            'codename': 'Oleg Makarov',
1588            'name': 'CloudLinux Server',
1589            'pretty_name': 'CloudLinux Server 6.8 (Oleg Makarov)',
1590            'version': '6.8',
1591            'pretty_version': '6.8 (Oleg Makarov)',
1592            'best_version': '6.8',
1593            'major_version': '6',
1594            'minor_version': '8'
1595        }
1596        self._test_outcome(desired_outcome)
1597
1598    def test_cloudlinux7_release(self):
1599        desired_outcome = {
1600            'id': 'cloudlinux',
1601            'codename': 'Yury Malyshev',
1602            'name': 'CloudLinux',
1603            'pretty_name': 'CloudLinux 7.3 (Yury Malyshev)',
1604            'like': 'rhel fedora centos',
1605            'version': '7.3',
1606            'pretty_version': '7.3 (Yury Malyshev)',
1607            'best_version': '7.3',
1608            'major_version': '7',
1609            'minor_version': '3'
1610        }
1611        self._test_outcome(desired_outcome)
1612
1613
1614def _bad_os_listdir(path='.'):
1615    """ This function is used by TestOverallWithEtcNotReadable to simulate
1616    a folder that cannot be called with os.listdir() but files are still
1617    readable. Forces distro to guess which *-release files are available. """
1618    raise OSError()
1619
1620
1621@pytest.mark.skipIf(not IS_LINUX, reason='Irrelevant on non-linx')
1622class TestOverallWithEtcNotReadable(TestOverall):
1623    def setup_method(self, test_method):
1624        self._old_listdir = os.listdir
1625        os.listdir = _bad_os_listdir
1626        super(TestOverallWithEtcNotReadable, self).setup_method(test_method)
1627
1628    def teardown_method(self, test_method):
1629        super(TestOverallWithEtcNotReadable, self).teardown_method(test_method)
1630        if os.listdir is _bad_os_listdir:
1631            os.listdir = self._old_listdir
1632
1633
1634@pytest.mark.skipif(not IS_LINUX, reason='Irrelevant on non-linux')
1635class TestGetAttr(DistroTestCase):
1636    """Test the consistency between the results of
1637    `{source}_release_attr()` and `{source}_release_info()` for all
1638    distros in `DISTROS`.
1639    """
1640
1641    def _test_attr(self, info_method, attr_method):
1642        for dist in DISTROS:
1643            self._setup_for_distro(os.path.join(DISTROS_DIR, dist))
1644            _distro = distro.LinuxDistribution()
1645            info = getattr(_distro, info_method)()
1646            for key in info.keys():
1647                try:
1648                    assert info[key] == getattr(_distro, attr_method)(key)
1649                except AssertionError:
1650                    print("distro: {0}, key: {1}".format(dist, key))
1651
1652    def test_os_release_attr(self):
1653        self._test_attr('os_release_info', 'os_release_attr')
1654
1655    def test_lsb_release_attr(self):
1656        self._test_attr('lsb_release_info', 'lsb_release_attr')
1657
1658    def test_distro_release_attr(self):
1659        self._test_attr('distro_release_info', 'distro_release_attr')
1660
1661
1662@pytest.mark.skipif(not IS_LINUX, reason='Irrelevant on non-linux')
1663class TestInfo(DistroTestCase):
1664
1665    def setup_method(self, test_method):
1666        super(TestInfo, self).setup_method(test_method)
1667        self.ubuntu14_os_release = os.path.join(
1668            DISTROS_DIR, 'ubuntu14', 'etc', 'os-release')
1669
1670    def test_info(self):
1671        _distro = distro.LinuxDistribution(
1672            False, self.ubuntu14_os_release, 'non')
1673
1674        desired_info = {
1675            'id': 'ubuntu',
1676            'version': '14.04',
1677            'like': 'debian',
1678            'version_parts': {
1679                'major': '14',
1680                'minor': '04',
1681                'build_number': ''
1682            },
1683            'codename': 'Trusty Tahr'
1684        }
1685
1686        info = _distro.info()
1687        assert info == desired_info
1688
1689        desired_info_diff = {
1690            'version': '14.04 (Trusty Tahr)'
1691        }
1692        desired_info.update(desired_info_diff)
1693        info = _distro.info(pretty=True)
1694        assert info == desired_info
1695
1696        desired_info_diff = {
1697            'version': '14.04.3',
1698            'version_parts': {
1699                'major': '14',
1700                'minor': '04',
1701                'build_number': '3'
1702            }
1703        }
1704        desired_info.update(desired_info_diff)
1705        info = _distro.info(best=True)
1706        assert info == desired_info
1707
1708        desired_info_diff = {
1709            'version': '14.04.3 (Trusty Tahr)'
1710        }
1711        desired_info.update(desired_info_diff)
1712        info = _distro.info(pretty=True, best=True)
1713        assert info == desired_info
1714
1715    def test_none(self):
1716
1717        def _test_none(info):
1718            assert info['id'] == ''
1719            assert info['version'] == ''
1720            assert info['like'] == ''
1721            assert info['version_parts']['major'] == ''
1722            assert info['version_parts']['minor'] == ''
1723            assert info['version_parts']['build_number'] == ''
1724            assert info['codename'] == ''
1725
1726        _distro = distro.LinuxDistribution(False, 'non', 'non')
1727
1728        info = _distro.info()
1729        _test_none(info)
1730
1731        info = _distro.info(best=True)
1732        _test_none(info)
1733
1734        info = _distro.info(pretty=True)
1735        _test_none(info)
1736
1737        info = _distro.info(pretty=True, best=True)
1738        _test_none(info)
1739
1740    def test_linux_distribution(self):
1741        _distro = distro.LinuxDistribution(False, self.ubuntu14_os_release)
1742        i = _distro.linux_distribution()
1743        assert i == ('Ubuntu', '14.04', 'Trusty Tahr')
1744
1745    def test_linux_distribution_full_false(self):
1746        _distro = distro.LinuxDistribution(False, self.ubuntu14_os_release)
1747        i = _distro.linux_distribution(full_distribution_name=False)
1748        assert i == ('ubuntu', '14.04', 'Trusty Tahr')
1749
1750    def test_all(self):
1751        """Test info() by comparing its results with the results of specific
1752        consolidated accessor functions.
1753        """
1754        def _test_all(info, best=False, pretty=False):
1755            assert info['id'] == _distro.id()
1756            assert info['version'] == _distro.version(pretty=pretty, best=best)
1757            assert info['version_parts']['major'] == \
1758                _distro.major_version(best=best)
1759            assert info['version_parts']['minor'] == \
1760                _distro.minor_version(best=best)
1761            assert info['version_parts']['build_number'] == \
1762                _distro.build_number(best=best)
1763            assert info['like'] == _distro.like()
1764            assert info['codename'] == _distro.codename()
1765            assert len(info['version_parts']) == 3
1766            assert len(info) == 5
1767
1768        for dist in DISTROS:
1769            self._setup_for_distro(os.path.join(DISTROS_DIR, dist))
1770
1771            _distro = distro.LinuxDistribution()
1772
1773            info = _distro.info()
1774            _test_all(info)
1775
1776            info = _distro.info(best=True)
1777            _test_all(info, best=True)
1778
1779            info = _distro.info(pretty=True)
1780            _test_all(info, pretty=True)
1781
1782            info = _distro.info(pretty=True, best=True)
1783            _test_all(info, pretty=True, best=True)
1784
1785
1786@pytest.mark.skipif(not IS_LINUX, reason='Irrelevant on non-linux')
1787class TestOSReleaseParsing:
1788    """Test the parsing of os-release files.
1789    """
1790
1791    def setup_method(self, test_method):
1792        self.distro = distro.LinuxDistribution(False, None, None)
1793        self.distro.debug = True
1794
1795    def _get_props(self, input):
1796        return self.distro._parse_os_release_content(StringIO(
1797            input,
1798        ))
1799
1800    def _test_zero_length_props(self, input):
1801        props = self._get_props(input)
1802        assert len(props) == 0
1803
1804    def _test_empty_value(self, input):
1805        props = self._get_props(input)
1806        assert props.get('key', None) == ''
1807
1808    def _test_parsed_value(self, input):
1809        props = self._get_props(input)
1810        assert props.get('key', None) == 'value'
1811
1812    def test_kv_01_empty_file(self):
1813        self._test_zero_length_props('')
1814
1815    def test_kv_02_empty_line(self):
1816        self._test_zero_length_props('\n')
1817
1818    def test_kv_03_empty_line_with_crlf(self):
1819        self._test_zero_length_props('\r\n')
1820
1821    def test_kv_04_empty_line_with_just_cr(self):
1822        self._test_zero_length_props('\r')
1823
1824    def test_kv_05_comment(self):
1825        self._test_zero_length_props('# KEY=value\n')
1826
1827    def test_kv_06_empty_value(self):
1828        self._test_empty_value('KEY=\n')
1829
1830    def test_kv_07_empty_value_single_quoted(self):
1831        self._test_empty_value('KEY=\'\'\n')
1832
1833    def test_kv_08_empty_value_double_quoted(self):
1834        self._test_empty_value('KEY=""\n')
1835
1836    def test_kv_09_word(self):
1837        self._test_parsed_value('KEY=value\n')
1838
1839    def test_kv_10_word_no_newline(self):
1840        self._test_parsed_value('KEY=value')
1841
1842    def test_kv_11_word_with_crlf(self):
1843        self._test_parsed_value('KEY=value\r\n')
1844
1845    def test_kv_12_word_with_just_cr(self):
1846        self._test_parsed_value('KEY=value\r')
1847
1848    def test_kv_13_word_with_multi_blanks(self):
1849        self._test_empty_value('KEY=  cmd   \n')
1850        # Note: Without quotes, this assigns the empty string, and 'cmd' is
1851        # a separate token that is being ignored (it would be a command
1852        # in the shell).
1853
1854    def test_kv_14_unquoted_words(self):
1855        self._test_parsed_value('KEY=value cmd\n')
1856
1857    def test_kv_15_double_quoted_words(self):
1858        props = self._get_props('KEY="a simple value" cmd\n')
1859        assert props.get('key', None) == 'a simple value'
1860
1861    def test_kv_16_double_quoted_words_with_multi_blanks(self):
1862        props = self._get_props('KEY=" a  simple   value "\n')
1863        assert props.get('key', None) == ' a  simple   value '
1864
1865    def test_kv_17_double_quoted_word_with_single_quote(self):
1866        props = self._get_props('KEY="it\'s value"\n')
1867        assert props.get('key', None) == 'it\'s value'
1868
1869    def test_kv_18_double_quoted_word_with_double_quote(self):
1870        props = self._get_props('KEY="a \\"bold\\" move"\n')
1871        assert props.get('key', None) == 'a "bold" move'
1872
1873    def test_kv_19_single_quoted_words(self):
1874        props = self._get_props('KEY=\'a simple value\'\n')
1875        assert props.get('key', None) == 'a simple value'
1876
1877    def test_kv_20_single_quoted_words_with_multi_blanks(self):
1878        props = self._get_props('KEY=\' a  simple   value \'\n')
1879        assert props.get('key', None) == ' a  simple   value '
1880
1881    def test_kv_21_single_quoted_word_with_double_quote(self):
1882        props = self._get_props('KEY=\'a "bold" move\'\n')
1883        assert props.get('key', None) == 'a "bold" move'
1884
1885    def test_kv_22_quoted_unicode_wordchar(self):
1886        # "wordchar" means it is in the shlex.wordchars variable.
1887        props = self._get_props(u'KEY="wordchar: \u00CA (E accent grave)"\n')
1888        assert props.get('key', None) == u'wordchar: \u00CA (E accent grave)'
1889
1890    def test_kv_23_quoted_unicode_non_wordchar(self):
1891        # "non-wordchar" means it is not in the shlex.wordchars variable.
1892        props = self._get_props(
1893            u'KEY="non-wordchar: \u00A1 (inverted exclamation mark)"\n')
1894        assert (props.get('key', None) ==
1895                u'non-wordchar: \u00A1 (inverted exclamation mark)')
1896
1897    def test_kv_24_double_quoted_entire_single_quoted_word(self):
1898        props = self._get_props('KEY="\'value\'"\n')
1899        assert props.get('key', None) == "'value'"
1900
1901    def test_kv_25_single_quoted_entire_double_quoted_word(self):
1902        props = self._get_props('KEY=\'"value"\'\n')
1903        assert props.get('key', None) == '"value"'
1904
1905    def test_kv_26_double_quoted_multiline(self):
1906        props = self.distro._parse_os_release_content(StringIO(
1907            'KEY="a multi\n'
1908            'line value"\n'
1909        ))
1910        assert props.get('key', None) == 'a multi\nline value'
1911        # TODO: Find out why the result is not 'a multi line value'
1912
1913    def test_kv_27_double_quoted_multiline_2(self):
1914        props = self._get_props('KEY=\' a  simple   value \'\n')
1915        props = self.distro._parse_os_release_content(StringIO(
1916            'KEY="a multi\n'
1917            'line=value"\n'
1918        ))
1919        assert props.get('key', None) == 'a multi\nline=value'
1920        # TODO: Find out why the result is not 'a multi line=value'
1921
1922    def test_kv_28_double_quoted_word_with_equal(self):
1923        props = self._get_props('KEY="var=value"\n')
1924        assert props.get('key', None) == 'var=value'
1925
1926    def test_kv_29_single_quoted_word_with_equal(self):
1927        props = self._get_props('KEY=\'var=value\'\n')
1928        assert props.get('key', None) == 'var=value'
1929
1930    def test_kx_01(self):
1931        props = self.distro._parse_os_release_content(StringIO(
1932            'KEY1=value1\n'
1933            'KEY2="value  2"\n'
1934        ))
1935        assert props.get('key1', None) == 'value1'
1936        assert props.get('key2', None) == 'value  2'
1937
1938    def test_kx_02(self):
1939        props = self.distro._parse_os_release_content(StringIO(
1940            '# KEY1=value1\n'
1941            'KEY2="value  2"\n'
1942        ))
1943        assert props.get('key1', None) is None
1944        assert props.get('key2', None) == 'value  2'
1945
1946
1947@pytest.mark.skipif(not IS_LINUX, reason='Irrelevant on non-linux')
1948class TestGlobal:
1949    """Test the global module-level functions, and default values of their
1950    arguments.
1951    """
1952
1953    def setup_method(self, test_method):
1954        pass
1955
1956    def test_global(self):
1957        # Because the module-level functions use the module-global
1958        # LinuxDistribution instance, it would influence the tested
1959        # code too much if we mocked that in order to use the distro
1960        # specific release files. Instead, we let the functions use
1961        # the release files of the distro this test runs on, and
1962        # compare the result of the global functions with the result
1963        # of the methods on the global LinuxDistribution object.
1964
1965        def _test_consistency(function, kwargs=None):
1966            kwargs = kwargs or {}
1967            method_result = getattr(MODULE_DISTRO, function)(**kwargs)
1968            function_result = getattr(distro, function)(**kwargs)
1969            assert method_result == function_result
1970
1971        kwargs = {'full_distribution_name': True}
1972        _test_consistency('linux_distribution', kwargs)
1973        kwargs = {'full_distribution_name': False}
1974        _test_consistency('linux_distribution', kwargs)
1975
1976        kwargs = {'pretty': False}
1977        _test_consistency('name', kwargs)
1978        _test_consistency('version', kwargs)
1979        _test_consistency('info', kwargs)
1980
1981        kwargs = {'pretty': True}
1982        _test_consistency('name', kwargs)
1983        _test_consistency('version', kwargs)
1984        _test_consistency('info', kwargs)
1985
1986        kwargs = {'best': False}
1987        _test_consistency('version', kwargs)
1988        _test_consistency('version_parts', kwargs)
1989        _test_consistency('major_version', kwargs)
1990        _test_consistency('minor_version', kwargs)
1991        _test_consistency('build_number', kwargs)
1992        _test_consistency('info', kwargs)
1993
1994        kwargs = {'best': True}
1995        _test_consistency('version', kwargs)
1996        _test_consistency('version_parts', kwargs)
1997        _test_consistency('major_version', kwargs)
1998        _test_consistency('minor_version', kwargs)
1999        _test_consistency('build_number', kwargs)
2000        _test_consistency('info', kwargs)
2001
2002        _test_consistency('id')
2003        _test_consistency('like')
2004        _test_consistency('codename')
2005        _test_consistency('info')
2006
2007        _test_consistency('os_release_info')
2008        _test_consistency('lsb_release_info')
2009        _test_consistency('distro_release_info')
2010        _test_consistency('uname_info')
2011
2012        os_release_keys = [
2013            'name',
2014            'version',
2015            'id',
2016            'id_like',
2017            'pretty_name',
2018            'version_id',
2019            'codename',
2020        ]
2021        for key in os_release_keys:
2022            _test_consistency('os_release_attr', {'attribute': key})
2023
2024        lsb_release_keys = [
2025            'distributor_id',
2026            'description',
2027            'release',
2028            'codename',
2029        ]
2030        for key in lsb_release_keys:
2031            _test_consistency('lsb_release_attr', {'attribute': key})
2032
2033        distro_release_keys = [
2034            'id',
2035            'name',
2036            'version_id',
2037            'codename',
2038        ]
2039        for key in distro_release_keys:
2040            _test_consistency('distro_release_attr', {'attribute': key})
2041
2042        uname_keys = [
2043            'id',
2044            'name',
2045            'release'
2046        ]
2047        for key in uname_keys:
2048            _test_consistency('uname_attr', {'attribute': key})
2049
2050
2051@pytest.mark.skipif(not IS_LINUX, reason='Irrelevant on non-linux')
2052class TestRepr:
2053    """Test the __repr__() method.
2054    """
2055
2056    def test_repr(self):
2057        # We test that the class name and the names of all instance attributes
2058        # show up in the repr() string.
2059        repr_str = repr(distro._distro)
2060        assert "LinuxDistribution" in repr_str
2061        for attr in MODULE_DISTRO.__dict__.keys():
2062            assert attr + '=' in repr_str
2063