mirror of
https://github.com/HorlogeSkynet/archey4
synced 2025-05-19 16:00:27 +02:00
Compare commits
2 Commits
d4cbd72bae
...
f545d948c0
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f545d948c0 | ||
![]() |
73c1f68e39 |
README.mdarchey.1
archey
__main__.pyconfiguration.pyconstants.pyscreenshot.py
setup.pytest
entries
__init__.pytest_archey_cpu.pytest_archey_desktop_environment.pytest_archey_disk.pytest_archey_distro.pytest_archey_gpu.pytest_archey_hostname.pytest_archey_kernel.pytest_archey_lan_ip.pytest_archey_model.pytest_archey_packages.pytest_archey_ram.pytest_archey_shell.pytest_archey_temperature.pytest_archey_terminal.pytest_archey_uptime.pytest_archey_user.pytest_archey_wan_ip.pytest_archey_window_manager.py
test_archey_configuration.py@ -140,13 +140,13 @@ sudo mv dist/archey /usr/local/bin/
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
archey
|
||||
archey --help
|
||||
```
|
||||
|
||||
or if you only want to try this out (for instance, from source) :
|
||||
|
||||
```bash
|
||||
python3 -m archey
|
||||
python3 -m archey --help
|
||||
```
|
||||
|
||||
## Configuration (optional)
|
||||
|
6
archey.1
6
archey.1
@ -31,7 +31,7 @@ Remain \fImaintained\fR, \fIcommunity-driven\fR and
|
||||
.IP "-h, --help"
|
||||
show help message and exit
|
||||
|
||||
.IP "-c, --config-path"
|
||||
.IP "-c, --config-path PATH"
|
||||
path to a configuration file, or a directory containing a `config.json`
|
||||
|
||||
.IP "-d, --distribution IDENTIFIER"
|
||||
@ -41,6 +41,10 @@ supported distribution identifier to show the logo of, pass `unknown` to list th
|
||||
output entries data to JSON format, use multiple times to increase
|
||||
indentation
|
||||
|
||||
.IP "-s, --screenshot [FILENAME]"
|
||||
take a screenshot once execution is done, optionally specify a target
|
||||
path
|
||||
|
||||
.IP "-v, --version"
|
||||
show program's version number and exit
|
||||
|
||||
|
@ -18,6 +18,7 @@ from archey.output import Output
|
||||
from archey.configuration import Configuration
|
||||
from archey.distributions import Distributions
|
||||
from archey.processes import Processes
|
||||
from archey.screenshot import take_screenshot
|
||||
from archey.entries.user import User as e_User
|
||||
from archey.entries.hostname import Hostname as e_Hostname
|
||||
from archey.entries.model import Model as e_Model
|
||||
@ -71,6 +72,7 @@ def args_parsing():
|
||||
parser = argparse.ArgumentParser(prog='archey')
|
||||
parser.add_argument(
|
||||
'-c', '--config-path',
|
||||
metavar='PATH',
|
||||
help='path to a configuration file, or a directory containing a `config.json`'
|
||||
)
|
||||
parser.add_argument(
|
||||
@ -84,6 +86,13 @@ def args_parsing():
|
||||
action='count',
|
||||
help='output entries data to JSON format, use multiple times to increase indentation'
|
||||
)
|
||||
parser.add_argument(
|
||||
'-s', '--screenshot',
|
||||
metavar='PATH',
|
||||
nargs='?',
|
||||
const=False,
|
||||
help='take a screenshot once execution is done, optionally specify a target path'
|
||||
)
|
||||
parser.add_argument(
|
||||
'-v', '--version',
|
||||
action='version',
|
||||
@ -137,6 +146,11 @@ def main():
|
||||
|
||||
output.output()
|
||||
|
||||
# Has the screenshot flag been specified ?
|
||||
if args.screenshot is not None:
|
||||
# If so, but still _falsy_, pass `None` as no output file has been specified by the user.
|
||||
take_screenshot((args.screenshot or None))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
@ -3,67 +3,22 @@
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
from copy import deepcopy
|
||||
|
||||
from archey.constants import DEFAULT_CONFIG
|
||||
from archey.singleton import Singleton
|
||||
|
||||
|
||||
class Configuration(metaclass=Singleton):
|
||||
"""
|
||||
The default needed configuration which will be used by Archey is present below.
|
||||
Values present in the `self._config` dictionary below are needed.
|
||||
New optional values may be added with `_update_recursive` method.
|
||||
Values present in `archey.constants.DEFAULT_CONFIG` dictionary are required.
|
||||
New optional values may be added with `update_recursive` method.
|
||||
|
||||
If a `config_path` is passed during instantiation, it will be loaded.
|
||||
"""
|
||||
def __init__(self, config_path=None):
|
||||
self._config = {
|
||||
'allow_overriding': True,
|
||||
'parallel_loading': True,
|
||||
'suppress_warnings': False,
|
||||
'colors_palette': {
|
||||
'use_unicode': True,
|
||||
'honor_ansi_color': True
|
||||
},
|
||||
'disk': {
|
||||
'show_filesystems': ['local'],
|
||||
'combine_total': True,
|
||||
'disk_labels': None,
|
||||
'hide_entry_name': None
|
||||
},
|
||||
'default_strings': {
|
||||
'no_address': 'No Address',
|
||||
'not_detected': 'Not detected',
|
||||
'virtual_environment': 'Virtual Environment'
|
||||
},
|
||||
'gpu': {
|
||||
'one_line': True,
|
||||
'max_count': 2
|
||||
},
|
||||
'ip_settings': {
|
||||
'lan_ip_max_count': 2,
|
||||
'lan_ip_v6_support': True,
|
||||
'wan_ip_v6_support': True
|
||||
},
|
||||
'limits': {
|
||||
'ram': {
|
||||
'warning': 33.3,
|
||||
'danger': 66.7
|
||||
},
|
||||
'disk': {
|
||||
'warning': 50,
|
||||
'danger': 75
|
||||
}
|
||||
},
|
||||
'temperature': {
|
||||
'char_before_unit': ' ',
|
||||
'sensors_chipsets': [],
|
||||
'use_fahrenheit': False
|
||||
},
|
||||
'timeout': {
|
||||
'ipv4_detection': 1,
|
||||
'ipv6_detection': 1
|
||||
}
|
||||
}
|
||||
# Deep-copy `DEFAULT_CONFIG` so we have a local copy to safely mutate.
|
||||
self._config = deepcopy(DEFAULT_CONFIG)
|
||||
|
||||
# Let's "save" `STDERR` file descriptor for `suppress_warnings` option
|
||||
self._stderr = sys.stderr
|
||||
@ -99,7 +54,7 @@ class Configuration(metaclass=Singleton):
|
||||
|
||||
try:
|
||||
with open(path) as f_config:
|
||||
self._update_recursive(self._config, json.load(f_config))
|
||||
self.update_recursive(self._config, json.load(f_config))
|
||||
except FileNotFoundError:
|
||||
return
|
||||
# For backward compatibility with Python versions prior to 3.5.0
|
||||
@ -116,7 +71,8 @@ class Configuration(metaclass=Singleton):
|
||||
else:
|
||||
self._close_and_restore_sys_stderr()
|
||||
|
||||
def _update_recursive(self, old_dict, new_dict):
|
||||
@classmethod
|
||||
def update_recursive(cls, old_dict, new_dict):
|
||||
"""
|
||||
A method for recursively merging dictionaries as `dict.update()` is not able to do this.
|
||||
Original snippet taken from here : <https://gist.github.com/angstwad/bf22d1822c38a92ec0a9>
|
||||
@ -125,7 +81,7 @@ class Configuration(metaclass=Singleton):
|
||||
if key in old_dict \
|
||||
and isinstance(old_dict[key], dict) \
|
||||
and isinstance(value, dict):
|
||||
self._update_recursive(old_dict[key], value)
|
||||
cls.update_recursive(old_dict[key], value)
|
||||
else:
|
||||
old_dict[key] = value
|
||||
|
||||
@ -137,3 +93,7 @@ class Configuration(metaclass=Singleton):
|
||||
|
||||
def __del__(self):
|
||||
self._close_and_restore_sys_stderr()
|
||||
|
||||
def __iter__(self):
|
||||
"""When used as an iterator, directly yield `_config` elements"""
|
||||
return iter(self._config.items())
|
||||
|
@ -1,4 +1,8 @@
|
||||
"""Logos colors and distributions / logos matching"""
|
||||
"""
|
||||
Logos colors definition.
|
||||
Distributions / logos correspondences.
|
||||
Default configuration.
|
||||
"""
|
||||
|
||||
import archey.logos as logos
|
||||
|
||||
@ -56,3 +60,54 @@ LOGOS_DICT = {
|
||||
Distributions.UBUNTU: logos.UBUNTU,
|
||||
Distributions.WINDOWS: logos.WINDOWS
|
||||
}
|
||||
|
||||
|
||||
# The default needed configuration which will be used by Archey is present below.
|
||||
DEFAULT_CONFIG = {
|
||||
'allow_overriding': True,
|
||||
'parallel_loading': True,
|
||||
'suppress_warnings': False,
|
||||
'colors_palette': {
|
||||
'use_unicode': True,
|
||||
'honor_ansi_color': True
|
||||
},
|
||||
'disk': {
|
||||
'show_filesystems': ['local'],
|
||||
'combine_total': True,
|
||||
'disk_labels': None,
|
||||
'hide_entry_name': None
|
||||
},
|
||||
'default_strings': {
|
||||
'no_address': 'No Address',
|
||||
'not_detected': 'Not detected',
|
||||
'virtual_environment': 'Virtual Environment'
|
||||
},
|
||||
'gpu': {
|
||||
'one_line': True,
|
||||
'max_count': 2
|
||||
},
|
||||
'ip_settings': {
|
||||
'lan_ip_max_count': 2,
|
||||
'lan_ip_v6_support': True,
|
||||
'wan_ip_v6_support': True
|
||||
},
|
||||
'limits': {
|
||||
'ram': {
|
||||
'warning': 33.3,
|
||||
'danger': 66.7
|
||||
},
|
||||
'disk': {
|
||||
'warning': 50,
|
||||
'danger': 75
|
||||
}
|
||||
},
|
||||
'temperature': {
|
||||
'char_before_unit': ' ',
|
||||
'sensors_chipsets': [],
|
||||
'use_fahrenheit': False
|
||||
},
|
||||
'timeout': {
|
||||
'ipv4_detection': 1,
|
||||
'ipv6_detection': 1
|
||||
}
|
||||
}
|
||||
|
92
archey/screenshot.py
Normal file
92
archey/screenshot.py
Normal file
@ -0,0 +1,92 @@
|
||||
"""Simple module doing its best as taking a screenshot of the current screen"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
from contextlib import ExitStack
|
||||
from datetime import datetime
|
||||
from functools import partial
|
||||
from subprocess import CalledProcessError, DEVNULL, check_call
|
||||
|
||||
|
||||
def take_screenshot(output_file=None):
|
||||
"""
|
||||
Simple function trying to take a screenshot using various famous back-end programs.
|
||||
When supported by the found and available back-end, try to honor `output_file`.
|
||||
"""
|
||||
if not output_file or os.path.isdir(output_file):
|
||||
# When a directory is provided, we've to force `output_file` to represent a **file** path.
|
||||
output_file = os.path.join(
|
||||
(output_file or os.getcwd()),
|
||||
datetime.now().strftime('archey4_screenshot_%Y-%m-%d_%H.%M.%S.png')
|
||||
)
|
||||
|
||||
# Some programs don't accept specific filename as parameters.
|
||||
# In such cases, we may provide them a target directory instead.
|
||||
output_dir = os.path.dirname(output_file)
|
||||
|
||||
# Back-end programs that _may_ (?) be available across different platforms.
|
||||
screenshot_tools = {
|
||||
'Flameshot': ['flameshot', 'full', '-p', output_dir],
|
||||
'ImageMagick': ['import', '-window', 'root', output_file],
|
||||
'scrot': ['scrot', '-z', output_file],
|
||||
'Shutter': ['shutter', '-f', '-o', output_file, '-e'],
|
||||
}
|
||||
|
||||
# Extends the original screenshot tools dictionary according to current platform.
|
||||
if sys.platform in ('win32', 'cygwin'):
|
||||
screenshot_tools['SnippingTool'] = ['SnippingTool.exe', '/clip']
|
||||
elif sys.platform == 'darwin':
|
||||
screenshot_tools['ScreenCapture'] = [
|
||||
'screencapture',
|
||||
'-x',
|
||||
'-t', output_file.rpart('.')[2],
|
||||
output_file
|
||||
]
|
||||
else: # *NIX systems (and others)...
|
||||
screenshot_tools['Escrotum'] = ['escrotum', output_file]
|
||||
screenshot_tools['GNOME-Screenshot'] = ['gnome-screenshot', '-f', output_file]
|
||||
screenshot_tools['grim'] = ['grim', output_file]
|
||||
screenshot_tools['KDE-Spectacle'] = ['spectacle', '-b', '-o', output_file]
|
||||
screenshot_tools['Xfce4-Screenshooter'] = ['xfce4-screenshooter', '-f', '-s', output_dir]
|
||||
screenshot_tools['Screencap (Android)'] = [
|
||||
'screencap', # Binary available on Android.
|
||||
'-p', # It only accepts PNG as image output format.
|
||||
(output_file.rpart('.')[0] + '.png')
|
||||
]
|
||||
|
||||
# This part purposefully blocks so we wait a little bit before taking the screenshot.
|
||||
# It prevents taking a screenshot before Archey's output has appeared.
|
||||
for time_remaining in range(3, 0, -1):
|
||||
taking_sc_str = 'Taking screenshot in {:1d}...'.format(time_remaining)
|
||||
print(taking_sc_str, end='', flush=True)
|
||||
time.sleep(1)
|
||||
print('\r' + ' ' * len(taking_sc_str), end='\r', flush=True)
|
||||
time.sleep(0.5)
|
||||
|
||||
with ExitStack() as defer_stack:
|
||||
for screenshot_tool, screenshot_cmd in screenshot_tools.items():
|
||||
try:
|
||||
check_call(screenshot_cmd, stderr=DEVNULL)
|
||||
except FileNotFoundError:
|
||||
continue
|
||||
except CalledProcessError as process_error:
|
||||
defer_stack.callback(partial(
|
||||
print,
|
||||
'Couldn\'t take a screenshot with {}: \"{}\".'.format(
|
||||
screenshot_tool, process_error
|
||||
),
|
||||
file=sys.stderr
|
||||
))
|
||||
continue
|
||||
break
|
||||
else:
|
||||
defer_stack.callback(partial(
|
||||
print,
|
||||
"""\
|
||||
Sorry, we couldn\'t find any supported program to take a screenshot on your system.
|
||||
Please install one of the following and try again: {}.\
|
||||
""".format(', '.join(screenshot_tools.keys())),
|
||||
file=sys.stderr
|
||||
))
|
202
archey/test/entries/__init__.py
Normal file
202
archey/test/entries/__init__.py
Normal file
@ -0,0 +1,202 @@
|
||||
"""`archey.test.entries` module initialization file"""
|
||||
|
||||
from copy import deepcopy
|
||||
from functools import wraps
|
||||
|
||||
import unittest
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from archey.configuration import Configuration
|
||||
from archey.constants import DEFAULT_CONFIG
|
||||
from archey.entry import Entry
|
||||
|
||||
|
||||
class HelperMethods:
|
||||
"""
|
||||
This class contains helper methods we commonly use in our entry unit tests.
|
||||
We kindly borrow `update_recursive` class method from `Configuration` to DRY its implementation.
|
||||
"""
|
||||
@staticmethod
|
||||
def entry_mock(entry, configuration=None):
|
||||
"""
|
||||
Creates a placeholder "instance" of the entry class passed, with a clean default
|
||||
`_configuration` which is optionally updated by `configuration`.
|
||||
|
||||
It can be used to very cleanly unit-test instance methods of a class,
|
||||
by passing it in (after setting appropriate attributes).
|
||||
|
||||
The attributes defined are not instance attributes, however since this isn't
|
||||
technically an instance, they are used in place of the respective instance attributes.
|
||||
"""
|
||||
# We spec to the entry so non-existent methods can't be called...
|
||||
# ...and wrap it, to inherit its methods.
|
||||
instance_mock = MagicMock(spec=entry, wraps=entry)
|
||||
# These instance-attributes are quite important, so let's mimic them.
|
||||
instance_mock.name = str(entry.__name__)
|
||||
instance_mock.value = None # (entry default)
|
||||
|
||||
# Let's initially give the entry configuration the defaults.
|
||||
# We deep-copy `DEFAULT_CONFIG` to prevent its mutation.
|
||||
entry_configuration = deepcopy(DEFAULT_CONFIG)
|
||||
# Then, let's merge in `configuration` recursively.
|
||||
Configuration.update_recursive(entry_configuration, (configuration or {}))
|
||||
# Finally, replaces the internal (and private!) `_configuration` attribute by...
|
||||
# ... the corresponding configuration object.
|
||||
setattr(instance_mock, '_configuration', entry_configuration)
|
||||
|
||||
return instance_mock
|
||||
|
||||
@staticmethod
|
||||
def patch_clean_configuration(method_definition=None, *, configuration=None):
|
||||
"""
|
||||
Decorator for an entry test definition, which sets the entry's `_configuration` attribute to
|
||||
the Archey defaults, optionally updated with `configuration`.
|
||||
"""
|
||||
# Let's initially give the entry configuration the defaults.
|
||||
# We deep-copy `DEFAULT_CONFIG` to prevent its mutation.
|
||||
entry_configuration = deepcopy(DEFAULT_CONFIG)
|
||||
# Then, let's merge in `configuration` recursively.
|
||||
Configuration.update_recursive(entry_configuration, (configuration or {}))
|
||||
|
||||
def decorator_patch_clean_configuration(method):
|
||||
@wraps(method)
|
||||
def wrapper_patch_clean_configuration(*args, **kwargs):
|
||||
with patch('archey.entry.Configuration', autospec=True) as config_instance_mock:
|
||||
# Mock "publicly" used methods.
|
||||
config_instance_mock().get = entry_configuration.get
|
||||
config_instance_mock().__iter__ = lambda _: iter(entry_configuration.items())
|
||||
return method(*args, **kwargs)
|
||||
|
||||
return wrapper_patch_clean_configuration
|
||||
|
||||
if method_definition is None:
|
||||
return decorator_patch_clean_configuration
|
||||
|
||||
return decorator_patch_clean_configuration(method_definition)
|
||||
|
||||
|
||||
class TestHelperMethods(unittest.TestCase, HelperMethods):
|
||||
"""This class implements test cases for our helper methods."""
|
||||
class _SimpleEntry(Entry):
|
||||
"""A simple (sub-)class inheriting from `Entry` to use in testing."""
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'meaning_of_life'
|
||||
self.value = self.meaning_of_life()
|
||||
|
||||
def my_name(self):
|
||||
"""Returns the entry name."""
|
||||
return self.name
|
||||
|
||||
@staticmethod
|
||||
def meaning_of_life():
|
||||
"""Widely debated..."""
|
||||
return 42
|
||||
|
||||
def test_entry_mock_defaults(self):
|
||||
"""Test `entry_mock`s default attributes."""
|
||||
simple_mock_instance = self.entry_mock(TestHelperMethods._SimpleEntry)
|
||||
self.assertEqual(simple_mock_instance.name, '_SimpleEntry')
|
||||
self.assertIsNone(simple_mock_instance.value)
|
||||
self.assertDictEqual(simple_mock_instance._configuration, DEFAULT_CONFIG) # pylint: disable=protected-access
|
||||
|
||||
def test_entry_mock_spec(self):
|
||||
"""Test `entry_mock`s speccing."""
|
||||
simple_mock_instance = self.entry_mock(TestHelperMethods._SimpleEntry)
|
||||
with self.assertRaises(AttributeError):
|
||||
# We shouldn't be able to call methods that don't exist...
|
||||
simple_mock_instance.not_a_method()
|
||||
# ...or get attributes that don't exist.
|
||||
_ = simple_mock_instance.not_an_attribute
|
||||
# However we _should_ be able to set an attribute then use it.
|
||||
simple_mock_instance.is_simple = True
|
||||
self.assertTrue(simple_mock_instance.is_simple)
|
||||
|
||||
def test_entry_mock_wrap(self):
|
||||
"""Test `entry_mock`s class wrapping."""
|
||||
simple_mock_instance = self.entry_mock(TestHelperMethods._SimpleEntry)
|
||||
self.assertEqual(simple_mock_instance.meaning_of_life(), 42)
|
||||
simple_mock_instance.name = 'A simple entry!'
|
||||
self.assertEqual(simple_mock_instance.my_name(simple_mock_instance), 'A simple entry!')
|
||||
|
||||
@patch.dict(
|
||||
DEFAULT_CONFIG,
|
||||
values={
|
||||
'a_key': 'a_value',
|
||||
'a_dict': {
|
||||
'key_1': 1,
|
||||
'key_2': 2
|
||||
}
|
||||
},
|
||||
clear=True
|
||||
)
|
||||
def test_entry_mock_configuration_setting(self):
|
||||
"""Test `entry_mock`s configuration setting."""
|
||||
configuration_dict = {
|
||||
'another_key': 'another_value', # Adding a key-value pair.
|
||||
'a_dict': {
|
||||
'key_1': 10 # Updating a nested key-value pair.
|
||||
}
|
||||
}
|
||||
simple_mock_instance = self.entry_mock(TestHelperMethods._SimpleEntry, configuration_dict)
|
||||
self.assertDictEqual(
|
||||
simple_mock_instance._configuration, # pylint: disable=protected-access
|
||||
{
|
||||
'a_key': 'a_value',
|
||||
'another_key': 'another_value',
|
||||
'a_dict': {
|
||||
'key_1': 10,
|
||||
'key_2': 2
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
def test_patch_clean_configuration_defaults(self):
|
||||
"""Test the default configuration-setting of `patch_clean_configuration."""
|
||||
@HelperMethods.patch_clean_configuration
|
||||
def test(self):
|
||||
simple_entry = TestHelperMethods._SimpleEntry()
|
||||
self.assertDictEqual(
|
||||
dict(simple_entry._configuration), # pylint: disable=protected-access
|
||||
DEFAULT_CONFIG
|
||||
)
|
||||
|
||||
test(self)
|
||||
|
||||
@patch.dict(
|
||||
DEFAULT_CONFIG,
|
||||
values={
|
||||
'a_key': 'a_value',
|
||||
'a_dict': {
|
||||
'key_1': 1,
|
||||
'key_2': 2
|
||||
}
|
||||
},
|
||||
clear=True
|
||||
)
|
||||
def test_patch_clean_configuration_setting(self):
|
||||
"""Test `patch_clean_configuration`s configuration setting."""
|
||||
configuration_dict = {
|
||||
'another_key': 'another_value', # Adding a key-value pair.
|
||||
'a_dict': {
|
||||
'key_1': 10 # Updating a nested key-value pair.
|
||||
}
|
||||
}
|
||||
@HelperMethods.patch_clean_configuration(
|
||||
configuration=configuration_dict
|
||||
)
|
||||
def test(self):
|
||||
simple_entry = TestHelperMethods._SimpleEntry()
|
||||
self.assertDictEqual(
|
||||
dict(simple_entry._configuration), # pylint: disable=protected-access
|
||||
{
|
||||
'a_key': 'a_value',
|
||||
'another_key': 'another_value',
|
||||
'a_dict': {
|
||||
'key_1': 10,
|
||||
'key_2': 2
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
test(self)
|
@ -6,6 +6,7 @@ from unittest.mock import call, patch, MagicMock
|
||||
|
||||
from archey.colors import Colors
|
||||
from archey.entries.disk import Disk
|
||||
from archey.test.entries import HelperMethods
|
||||
|
||||
|
||||
class TestDiskEntry(unittest.TestCase):
|
||||
@ -13,29 +14,9 @@ class TestDiskEntry(unittest.TestCase):
|
||||
Here, we mock `check_output` calls to disk utility tools.
|
||||
"""
|
||||
def setUp(self):
|
||||
"""Some useful setup tasks to do before each test, to help us DRY."""
|
||||
self.disk_instance_mock = MagicMock(spec=Disk, wraps=Disk)
|
||||
"""We use these mocks so often, it's worth defining them here."""
|
||||
self.disk_instance_mock = HelperMethods.entry_mock(Disk)
|
||||
self.output_mock = MagicMock()
|
||||
# Let's set `Disk` instance mock's attributes to sensible defaults.
|
||||
self.disk_instance_mock.name = 'Disk'
|
||||
self.disk_instance_mock.value = None
|
||||
# We can always change this configuration in tests if need be.
|
||||
self.disk_instance_mock._configuration = { # pylint: disable=protected-access
|
||||
'disk': {
|
||||
'show_filesystems': ['local'],
|
||||
'combine_total': True,
|
||||
'disk_labels': None,
|
||||
'hide_entry_name': None
|
||||
},
|
||||
'limits': {
|
||||
'disk': {
|
||||
'warning': 50,
|
||||
'danger': 75
|
||||
}
|
||||
},
|
||||
# Required by all entries:
|
||||
'default_strings': {'not_detected': 'Not detected'}
|
||||
}
|
||||
|
||||
def test_disk_get_local_filesystems(self):
|
||||
"""Tests `Disk._get_local_filesystems`."""
|
@ -4,6 +4,8 @@ import unittest
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from archey.entries.distro import Distro
|
||||
from archey.test.entries import HelperMethods
|
||||
from archey.constants import DEFAULT_CONFIG
|
||||
|
||||
|
||||
class TestDistroEntry(unittest.TestCase):
|
||||
@ -37,11 +39,8 @@ ARCHITECTURE
|
||||
'archey.entries.distro.Distributions.get_distro_name',
|
||||
return_value=None # Soft-failing : No _pretty_ distribution name found...
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
return_value={'not_detected': 'Not detected'}
|
||||
)
|
||||
def test_unknown_distro_output(self, _, __, ___):
|
||||
@HelperMethods.patch_clean_configuration
|
||||
def test_unknown_distro_output(self, _, __):
|
||||
"""Test for `distro` and `uname` outputs concatenation"""
|
||||
distro = Distro()
|
||||
|
||||
@ -57,7 +56,7 @@ ARCHITECTURE
|
||||
)
|
||||
self.assertEqual(
|
||||
output_mock.append.call_args[0][1],
|
||||
'Not detected [ARCHITECTURE]'
|
||||
DEFAULT_CONFIG['default_strings']['not_detected'] + ' [ARCHITECTURE]'
|
||||
)
|
||||
|
||||
|
@ -5,18 +5,14 @@ from unittest.mock import MagicMock, patch
|
||||
|
||||
from subprocess import CalledProcessError
|
||||
|
||||
from archey.test import CustomAssertions
|
||||
from archey.entries.gpu import GPU
|
||||
from archey.test import CustomAssertions
|
||||
from archey.test.entries import HelperMethods
|
||||
from archey.constants import DEFAULT_CONFIG
|
||||
|
||||
|
||||
class TestGPUEntry(unittest.TestCase, CustomAssertions):
|
||||
"""Here, we mock the `check_output` call to `lspci` to test the logic"""
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
side_effect=[
|
||||
{'max_count': None}
|
||||
]
|
||||
)
|
||||
@patch(
|
||||
'archey.entries.gpu.check_output',
|
||||
return_value="""\
|
||||
@ -25,17 +21,11 @@ XX:YY.H SMBus: BBBBBBBBBBBBBBBB
|
||||
XX:YY.H VGA compatible controller: GPU-MODEL-NAME
|
||||
XX:YY.H Audio device: DDDDDDDDDDDDDDDD
|
||||
""")
|
||||
def test_match_vga(self, _, __):
|
||||
@HelperMethods.patch_clean_configuration
|
||||
def test_match_vga(self, _):
|
||||
"""Simple 'VGA' device type matching"""
|
||||
self.assertListEqual(GPU().value, ['GPU-MODEL-NAME'])
|
||||
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
side_effect=[
|
||||
{'max_count': 2},
|
||||
{'one_line': True}
|
||||
]
|
||||
)
|
||||
@patch(
|
||||
'archey.entries.gpu.check_output',
|
||||
return_value="""\
|
||||
@ -46,7 +36,15 @@ XX:YY.H Display controller: ANOTHER-MATCHING-VIDEO-CONTROLLER
|
||||
XX:YY.H Audio device: DDDDDDDDDDDDDDDD
|
||||
XX:YY.H 3D controller: 3D GPU-MODEL-NAME TAKES ADVANTAGE
|
||||
""")
|
||||
def test_multi_matches_capped_one_line(self, _, __):
|
||||
@HelperMethods.patch_clean_configuration(
|
||||
configuration={
|
||||
'gpu': {
|
||||
'one_line': True,
|
||||
'max_count': 2
|
||||
}
|
||||
}
|
||||
)
|
||||
def test_multi_matches_capped_one_line(self, _):
|
||||
"""
|
||||
Test detection when there are multiple graphical device candidates.
|
||||
Check that `max_count` and `one_line` are honored too, including on `output` overriding.
|
||||
@ -65,13 +63,6 @@ XX:YY.H 3D controller: 3D GPU-MODEL-NAME TAKES ADVANTAGE
|
||||
'3D GPU-MODEL-NAME TAKES ADVANTAGE, GPU-MODEL-NAME'
|
||||
)
|
||||
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
side_effect=[
|
||||
{'max_count': False},
|
||||
{'one_line': False}
|
||||
]
|
||||
)
|
||||
@patch(
|
||||
'archey.entries.gpu.check_output',
|
||||
return_value="""\
|
||||
@ -81,7 +72,15 @@ XX:YY.H Display controller: ANOTHER-MATCHING-VIDEO-CONTROLLER
|
||||
XX:YY.H Audio device: DDDDDDDDDDDDDDDD
|
||||
XX:YY.H 3D controller: 3D GPU-MODEL-NAME TAKES ADVANTAGE
|
||||
""")
|
||||
def test_multi_matches_uncapped_multiple_lines(self, _, __):
|
||||
@HelperMethods.patch_clean_configuration(
|
||||
configuration={
|
||||
'gpu': {
|
||||
'one_line': False,
|
||||
'max_count': False
|
||||
}
|
||||
}
|
||||
)
|
||||
def test_multi_matches_uncapped_multiple_lines(self, _):
|
||||
"""
|
||||
Test detection when there are multiple graphical device candidates.
|
||||
Check that `max_count` and `one_line` are honored too, including on `output` overriding.
|
||||
@ -104,14 +103,6 @@ XX:YY.H 3D controller: 3D GPU-MODEL-NAME TAKES ADVANTAGE
|
||||
'ANOTHER-MATCHING-VIDEO-CONTROLLER'
|
||||
)
|
||||
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
side_effect=[
|
||||
{'max_count': None},
|
||||
{'one_line': True},
|
||||
{'not_detected': 'Not detected'}
|
||||
]
|
||||
)
|
||||
@patch(
|
||||
'archey.entries.gpu.check_output',
|
||||
return_value="""\
|
||||
@ -119,7 +110,8 @@ XX:YY.H IDE interface: IIIIIIIIIIIIIIII
|
||||
XX:YY.H SMBus: BBBBBBBBBBBBBBBB
|
||||
XX:YY.H Audio device: DDDDDDDDDDDDDDDD
|
||||
""")
|
||||
def test_no_match(self, _, __):
|
||||
@HelperMethods.patch_clean_configuration
|
||||
def test_no_match(self, _):
|
||||
"""Test (non-)detection when there is not any graphical candidate"""
|
||||
gpu = GPU()
|
||||
|
||||
@ -129,22 +121,15 @@ XX:YY.H Audio device: DDDDDDDDDDDDDDDD
|
||||
self.assertListEmpty(gpu.value)
|
||||
self.assertEqual(
|
||||
output_mock.append.call_args[0][1],
|
||||
'Not detected'
|
||||
DEFAULT_CONFIG['default_strings']['not_detected']
|
||||
)
|
||||
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
side_effect=[
|
||||
{'max_count': None},
|
||||
{'one_line': False},
|
||||
{'not_detected': 'Not detected'}
|
||||
]
|
||||
)
|
||||
@patch(
|
||||
'archey.entries.gpu.check_output',
|
||||
side_effect=CalledProcessError(1, 'lspci')
|
||||
)
|
||||
def test_lspci_crash(self, _, __):
|
||||
@HelperMethods.patch_clean_configuration
|
||||
def test_lspci_crash(self, _):
|
||||
"""Test (non-)detection due to a crashing `lspci` program"""
|
||||
gpu = GPU()
|
||||
|
||||
@ -154,7 +139,7 @@ XX:YY.H Audio device: DDDDDDDDDDDDDDDD
|
||||
self.assertListEmpty(gpu.value)
|
||||
self.assertEqual(
|
||||
output_mock.append.call_args[0][1],
|
||||
'Not detected'
|
||||
DEFAULT_CONFIG['default_strings']['not_detected']
|
||||
)
|
||||
|
||||
|
@ -5,8 +5,10 @@ from unittest.mock import MagicMock, patch
|
||||
|
||||
from netifaces import AF_INET, AF_INET6, AF_LINK
|
||||
|
||||
from archey.test import CustomAssertions
|
||||
from archey.entries.lan_ip import LanIp
|
||||
from archey.test import CustomAssertions
|
||||
from archey.test.entries import HelperMethods
|
||||
from archey.constants import DEFAULT_CONFIG
|
||||
|
||||
|
||||
class TestLanIpEntry(unittest.TestCase, CustomAssertions):
|
||||
@ -46,14 +48,10 @@ class TestLanIpEntry(unittest.TestCase, CustomAssertions):
|
||||
}
|
||||
]
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
side_effect=[
|
||||
{'lan_ip_v6_support': None}, # Needed key.
|
||||
{'lan_ip_max_count': False}
|
||||
]
|
||||
@HelperMethods.patch_clean_configuration(
|
||||
configuration={'ip_settings': {'lan_ip_max_count': False}}
|
||||
)
|
||||
def test_multiple_interfaces(self, _, __, ___):
|
||||
def test_multiple_interfaces(self, _, __):
|
||||
"""Test for multiple interfaces, multiple addresses (including a loopback one)"""
|
||||
self.assertListEqual(
|
||||
LanIp().value,
|
||||
@ -109,14 +107,15 @@ class TestLanIpEntry(unittest.TestCase, CustomAssertions):
|
||||
}
|
||||
]
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
side_effect=[
|
||||
{'lan_ip_v6_support': True},
|
||||
{'lan_ip_max_count': 2}
|
||||
]
|
||||
@HelperMethods.patch_clean_configuration(
|
||||
configuration={
|
||||
'ip_settings': {
|
||||
'lan_ip_max_count': 2,
|
||||
'lan_ip_v6_support': True
|
||||
}
|
||||
}
|
||||
)
|
||||
def test_ipv6_and_limit_and_ether(self, _, __, ___):
|
||||
def test_ipv6_and_limit_and_ether(self, _, __):
|
||||
"""
|
||||
Test for IPv6 support, final set length limit and Ethernet interface filtering.
|
||||
Additionally check the `output` method behavior.
|
||||
@ -176,14 +175,10 @@ class TestLanIpEntry(unittest.TestCase, CustomAssertions):
|
||||
}
|
||||
]
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
side_effect=[
|
||||
{'lan_ip_v6_support': False},
|
||||
{'lan_ip_max_count': None}
|
||||
]
|
||||
@HelperMethods.patch_clean_configuration(
|
||||
configuration={'ip_settings': {'lan_ip_v6_support': False}}
|
||||
)
|
||||
def test_no_ipv6(self, _, __, ___):
|
||||
def test_no_ipv6(self, _, __):
|
||||
"""Test for IPv6 hiding"""
|
||||
self.assertListEqual(
|
||||
LanIp().value,
|
||||
@ -194,14 +189,8 @@ class TestLanIpEntry(unittest.TestCase, CustomAssertions):
|
||||
'archey.entries.lan_ip.netifaces.interfaces',
|
||||
return_value=[] # No interface returned by `netifaces`.
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
side_effect=[
|
||||
{'lan_ip_v6_support': None}, # Needed key.
|
||||
{'lan_ip_max_count': None} # Needed key.
|
||||
]
|
||||
)
|
||||
def test_no_network_interface(self, _, __):
|
||||
@HelperMethods.patch_clean_configuration
|
||||
def test_no_network_interface(self, _):
|
||||
"""Test when the device does not have any network interface"""
|
||||
self.assertListEmpty(LanIp().value)
|
||||
|
||||
@ -232,15 +221,8 @@ class TestLanIpEntry(unittest.TestCase, CustomAssertions):
|
||||
}
|
||||
]
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
side_effect=[
|
||||
{'lan_ip_v6_support': None}, # Needed key.
|
||||
{'lan_ip_max_count': None}, # Needed key.
|
||||
{'no_address': 'No address'}
|
||||
]
|
||||
)
|
||||
def test_no_network_address_output(self, _, __, ___):
|
||||
@HelperMethods.patch_clean_configuration
|
||||
def test_no_network_address_output(self, _, __):
|
||||
"""
|
||||
Test when the network interface(s) do not have any IP address.
|
||||
Additionally check the `output` method behavior.
|
||||
@ -253,7 +235,7 @@ class TestLanIpEntry(unittest.TestCase, CustomAssertions):
|
||||
self.assertListEmpty(lan_ip.value)
|
||||
self.assertEqual(
|
||||
output_mock.append.call_args[0][1],
|
||||
'No address'
|
||||
DEFAULT_CONFIG['default_strings']['no_address']
|
||||
)
|
||||
|
||||
@patch(
|
||||
@ -265,13 +247,8 @@ class TestLanIpEntry(unittest.TestCase, CustomAssertions):
|
||||
return_value=None, # Let's nastily mute class' outputs.
|
||||
create=True
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
side_effect=[
|
||||
{'not_detected': 'Not detected'}
|
||||
]
|
||||
)
|
||||
def test_netifaces_not_available(self, _, __):
|
||||
@HelperMethods.patch_clean_configuration
|
||||
def test_netifaces_not_available(self, _):
|
||||
"""Check `netifaces` is really acting as a (soft-)dependency"""
|
||||
lan_ip = LanIp()
|
||||
|
||||
@ -281,7 +258,7 @@ class TestLanIpEntry(unittest.TestCase, CustomAssertions):
|
||||
self.assertIsNone(lan_ip.value)
|
||||
self.assertEqual(
|
||||
output_mock.append.call_args[0][1],
|
||||
'Not detected'
|
||||
DEFAULT_CONFIG['default_strings']['not_detected']
|
||||
)
|
||||
|
||||
|
@ -6,6 +6,8 @@ import unittest
|
||||
from unittest.mock import MagicMock, mock_open, patch
|
||||
|
||||
from archey.entries.model import Model
|
||||
from archey.test.entries import HelperMethods
|
||||
from archey.constants import DEFAULT_CONFIG
|
||||
|
||||
|
||||
class TestModelEntry(unittest.TestCase):
|
||||
@ -24,6 +26,7 @@ class TestModelEntry(unittest.TestCase):
|
||||
mock_open(read_data='MY-LAPTOP-MODEL\n'),
|
||||
create=True
|
||||
)
|
||||
@HelperMethods.patch_clean_configuration
|
||||
def test_regular(self, _):
|
||||
"""Sometimes, it could be quite simple..."""
|
||||
self.assertEqual(Model().value, 'MY-LAPTOP-MODEL')
|
||||
@ -32,6 +35,7 @@ class TestModelEntry(unittest.TestCase):
|
||||
'archey.entries.model.check_output',
|
||||
side_effect=CalledProcessError(1, 'systemd-detect-virt', "none\n")
|
||||
)
|
||||
@HelperMethods.patch_clean_configuration
|
||||
def test_raspberry(self, _):
|
||||
"""Test for a typical Raspberry context"""
|
||||
with patch('archey.entries.model.open', mock_open(), create=True) as mock:
|
||||
@ -57,6 +61,7 @@ class TestModelEntry(unittest.TestCase):
|
||||
'MY-LAPTOP-MODEL\n' # `dmidecode` example output
|
||||
]
|
||||
)
|
||||
@HelperMethods.patch_clean_configuration
|
||||
def test_virtual_environment(self, _, __):
|
||||
"""Test for virtual machine"""
|
||||
self.assertEqual(
|
||||
@ -76,15 +81,12 @@ class TestModelEntry(unittest.TestCase):
|
||||
FileNotFoundError() # `dmidecode` call will fail
|
||||
]
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
return_value={'virtual_environment': 'Virtual Environment'}
|
||||
)
|
||||
def test_virtual_environment_without_dmidecode(self, _, __, ___):
|
||||
@HelperMethods.patch_clean_configuration
|
||||
def test_virtual_environment_without_dmidecode(self, _, __):
|
||||
"""Test for virtual machine (with a failing `dmidecode` call)"""
|
||||
self.assertEqual(
|
||||
Model().value,
|
||||
'Virtual Environment (xen, xen-domU)'
|
||||
DEFAULT_CONFIG['default_strings']['virtual_environment'] + ' (xen, xen-domU)'
|
||||
)
|
||||
|
||||
@patch(
|
||||
@ -95,13 +97,13 @@ class TestModelEntry(unittest.TestCase):
|
||||
'archey.entries.model.check_output',
|
||||
return_value='systemd-nspawn\n' # `systemd-detect-virt` example output
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
return_value={'virtual_environment': 'Virtual Environment'}
|
||||
)
|
||||
def test_virtual_environment_systemd_alone(self, _, __, ___):
|
||||
@HelperMethods.patch_clean_configuration
|
||||
def test_virtual_environment_systemd_alone(self, _, __):
|
||||
"""Test for virtual environments, with systemd tools and `dmidecode`"""
|
||||
self.assertEqual(Model().value, 'Virtual Environment (systemd-nspawn)')
|
||||
self.assertEqual(
|
||||
Model().value,
|
||||
DEFAULT_CONFIG['default_strings']['virtual_environment'] + ' (systemd-nspawn)'
|
||||
)
|
||||
|
||||
@patch(
|
||||
'archey.entries.model.os.getuid',
|
||||
@ -114,6 +116,7 @@ class TestModelEntry(unittest.TestCase):
|
||||
'MY-LAPTOP-MODEL\n' # `dmidecode` example output
|
||||
]
|
||||
)
|
||||
@HelperMethods.patch_clean_configuration
|
||||
def test_virtual_environment_systemd_and_dmidecode(self, _, __):
|
||||
"""Test for virtual environments, with systemd tools and `dmidecode`"""
|
||||
self.assertEqual(Model().value, 'MY-LAPTOP-MODEL (systemd-nspawn)')
|
||||
@ -126,11 +129,8 @@ class TestModelEntry(unittest.TestCase):
|
||||
'archey.entries.model.check_output',
|
||||
side_effect=FileNotFoundError()
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
return_value={'not_detected': 'Not detected'}
|
||||
)
|
||||
def test_no_match(self, _, __, ___):
|
||||
@HelperMethods.patch_clean_configuration
|
||||
def test_no_match(self, _, __):
|
||||
"""Test when no information could be retrieved"""
|
||||
with patch('archey.entries.model.open', mock_open(), create=True) as mock:
|
||||
mock.return_value.read.side_effect = [
|
||||
@ -146,7 +146,7 @@ class TestModelEntry(unittest.TestCase):
|
||||
self.assertIsNone(model.value)
|
||||
self.assertEqual(
|
||||
output_mock.append.call_args[0][1],
|
||||
'Not detected'
|
||||
DEFAULT_CONFIG['default_strings']['not_detected']
|
||||
)
|
||||
|
||||
|
@ -5,6 +5,8 @@ from unittest.mock import mock_open, patch, MagicMock
|
||||
|
||||
from archey.colors import Colors
|
||||
from archey.entries.ram import RAM
|
||||
from archey.test.entries import HelperMethods
|
||||
from archey.constants import DEFAULT_CONFIG
|
||||
|
||||
|
||||
class TestRAMEntry(unittest.TestCase):
|
||||
@ -19,16 +21,17 @@ class TestRAMEntry(unittest.TestCase):
|
||||
Mem: 15658 2043 10232 12 3382 13268
|
||||
Swap: 4095 39 4056
|
||||
""")
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
return_value={
|
||||
'ram': {
|
||||
'warning': 25,
|
||||
'danger': 45
|
||||
},
|
||||
@HelperMethods.patch_clean_configuration(
|
||||
configuration={
|
||||
'limits': {
|
||||
'ram': {
|
||||
'warning': 25,
|
||||
'danger': 45
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
def test_free_dash_m(self, _, __):
|
||||
def test_free_dash_m(self, _):
|
||||
"""Test `free -m` output parsing for low RAM use case"""
|
||||
output_mock = MagicMock()
|
||||
RAM().output(output_mock)
|
||||
@ -47,16 +50,17 @@ Swap: 4095 39 4056
|
||||
Mem: 7412 3341 1503 761 2567 3011
|
||||
Swap: 7607 5 7602
|
||||
""")
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
return_value={
|
||||
'ram': {
|
||||
'warning': 33.3,
|
||||
'danger': 66.7
|
||||
},
|
||||
@HelperMethods.patch_clean_configuration(
|
||||
configuration={
|
||||
'limits': {
|
||||
'ram': {
|
||||
'warning': 33.3,
|
||||
'danger': 66.7
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
def test_free_dash_m_warning(self, _, __):
|
||||
def test_free_dash_m_warning(self, _):
|
||||
"""Test `free -m` output parsing for warning RAM use case"""
|
||||
output_mock = MagicMock()
|
||||
RAM().output(output_mock)
|
||||
@ -75,16 +79,17 @@ Swap: 7607 5 7602
|
||||
Mem: 15658 12341 624 203 2692 2807
|
||||
Swap: 4095 160 3935
|
||||
""")
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
return_value={
|
||||
'ram': {
|
||||
'warning': 33.3,
|
||||
'danger': 66.7
|
||||
},
|
||||
@HelperMethods.patch_clean_configuration(
|
||||
configuration={
|
||||
'limits': {
|
||||
'ram': {
|
||||
'warning': 33.3,
|
||||
'danger': 66.7
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
def test_free_dash_m_danger(self, _, __):
|
||||
def test_free_dash_m_danger(self, _):
|
||||
"""Test `free -m` output parsing for danger RAM use case"""
|
||||
output_mock = MagicMock()
|
||||
RAM().output(output_mock)
|
||||
@ -151,13 +156,8 @@ SUnreclaim: 113308 kB
|
||||
side_effect=PermissionError(),
|
||||
create=True
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
side_effect=[
|
||||
{'not_detected': 'Not detected'}
|
||||
]
|
||||
)
|
||||
def test_not_detected(self, _, __, ___):
|
||||
@HelperMethods.patch_clean_configuration
|
||||
def test_not_detected(self, _, __):
|
||||
"""Check Archey does not crash when `/proc/meminfo` is not readable"""
|
||||
ram = RAM()
|
||||
|
||||
@ -167,7 +167,7 @@ SUnreclaim: 113308 kB
|
||||
self.assertIsNone(ram.value)
|
||||
self.assertEqual(
|
||||
output_mock.append.call_args[0][1],
|
||||
'Not detected'
|
||||
DEFAULT_CONFIG['default_strings']['not_detected']
|
||||
)
|
||||
|
||||
|
@ -6,6 +6,8 @@ import unittest
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from archey.entries.shell import Shell
|
||||
from archey.test.entries import HelperMethods
|
||||
from archey.constants import DEFAULT_CONFIG
|
||||
|
||||
|
||||
class TestShellEntry(unittest.TestCase):
|
||||
@ -44,11 +46,8 @@ class TestShellEntry(unittest.TestCase):
|
||||
'archey.entries.shell.check_output',
|
||||
side_effect=CalledProcessError(2, 'getent')
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
return_value={'not_detected': 'Not detected'}
|
||||
)
|
||||
def test_config_fall_back(self, _, __, ___):
|
||||
@HelperMethods.patch_clean_configuration
|
||||
def test_config_fall_back(self, _, __):
|
||||
"""`id` fails, but Archey must not !"""
|
||||
shell = Shell()
|
||||
|
||||
@ -58,7 +57,7 @@ class TestShellEntry(unittest.TestCase):
|
||||
self.assertIsNone(shell.value)
|
||||
self.assertEqual(
|
||||
output_mock.append.call_args[0][1],
|
||||
'Not detected'
|
||||
DEFAULT_CONFIG['default_strings']['not_detected']
|
||||
)
|
||||
|
||||
if __name__ == '__main__':
|
@ -10,6 +10,7 @@ from unittest.mock import MagicMock, patch
|
||||
|
||||
|
||||
from archey.entries.temperature import Temperature
|
||||
from archey.test.entries import HelperMethods
|
||||
|
||||
|
||||
class TestTemperatureEntry(unittest.TestCase):
|
||||
@ -48,15 +49,16 @@ class TestTemperatureEntry(unittest.TestCase):
|
||||
'archey.entries.temperature.iglob',
|
||||
return_value=[] # No temperature from file will be retrieved
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
side_effect=[
|
||||
{'sensors_chipsets': []},
|
||||
{'use_fahrenheit': False},
|
||||
{'char_before_unit': ' '}
|
||||
]
|
||||
@HelperMethods.patch_clean_configuration(
|
||||
configuration={
|
||||
'temperature': {
|
||||
'sensors_chipsets': [],
|
||||
'use_fahrenheit': False,
|
||||
'char_before_unit': ' '
|
||||
}
|
||||
}
|
||||
)
|
||||
def test_vcgencmd_only_no_max(self, _, __, ___):
|
||||
def test_vcgencmd_only_no_max(self, _, __):
|
||||
"""
|
||||
Test for `vcgencmd` output only (no sensor files).
|
||||
Only one value is retrieved, so no maximum should be displayed (see #39).
|
||||
@ -88,15 +90,16 @@ class TestTemperatureEntry(unittest.TestCase):
|
||||
]
|
||||
)
|
||||
@patch('archey.entries.temperature.iglob')
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
side_effect=[
|
||||
{'sensors_chipsets': []},
|
||||
{'use_fahrenheit': False},
|
||||
{'char_before_unit': ' '}
|
||||
]
|
||||
@HelperMethods.patch_clean_configuration(
|
||||
configuration={
|
||||
'temperature': {
|
||||
'sensors_chipsets': [],
|
||||
'use_fahrenheit': False,
|
||||
'char_before_unit': ' '
|
||||
}
|
||||
}
|
||||
)
|
||||
def test_vcgencmd_and_files(self, _, iglob_mock, __):
|
||||
def test_vcgencmd_and_files(self, iglob_mock, _):
|
||||
"""Tests `vcgencmd` output AND sensor files"""
|
||||
iglob_mock.return_value = iter([file.name for file in self._temp_files])
|
||||
self.assertDictEqual(
|
||||
@ -117,15 +120,16 @@ class TestTemperatureEntry(unittest.TestCase):
|
||||
]
|
||||
)
|
||||
@patch('archey.entries.temperature.iglob')
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
side_effect=[
|
||||
{'sensors_chipsets': []},
|
||||
{'use_fahrenheit': True},
|
||||
{'char_before_unit': '@'}
|
||||
]
|
||||
@HelperMethods.patch_clean_configuration(
|
||||
configuration={
|
||||
'temperature': {
|
||||
'sensors_chipsets': [],
|
||||
'use_fahrenheit': True,
|
||||
'char_before_unit': '@'
|
||||
}
|
||||
}
|
||||
)
|
||||
def test_files_only_in_fahrenheit(self, _, iglob_mock, __):
|
||||
def test_files_only_in_fahrenheit(self, iglob_mock, _):
|
||||
"""Test sensor files only, Fahrenheit (naive) conversion and special degree character"""
|
||||
iglob_mock.return_value = iter([file.name for file in self._temp_files])
|
||||
self.assertDictEqual(
|
||||
@ -149,14 +153,10 @@ class TestTemperatureEntry(unittest.TestCase):
|
||||
'archey.entries.temperature.iglob',
|
||||
return_value=[] # No temperature from file will be retrieved.
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
side_effect=[
|
||||
{'sensors_chipsets': []},
|
||||
{'not_detected': 'Not detected'}
|
||||
]
|
||||
@HelperMethods.patch_clean_configuration(
|
||||
configuration={'temperature': {'sensors_chipsets': []}}
|
||||
)
|
||||
def test_no_output(self, _, __, ___):
|
||||
def test_no_output(self, _, __):
|
||||
"""Test when no value could be retrieved (anyhow)"""
|
||||
self.assertIsNone(Temperature().value)
|
||||
|
||||
@ -221,15 +221,16 @@ class TestTemperatureEntry(unittest.TestCase):
|
||||
FileNotFoundError() # No temperature from `vcgencmd` call.
|
||||
]
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
side_effect=[
|
||||
{'sensors_chipsets': []},
|
||||
{'use_fahrenheit': True},
|
||||
{'char_before_unit': ' '}
|
||||
]
|
||||
@HelperMethods.patch_clean_configuration(
|
||||
configuration={
|
||||
'temperature': {
|
||||
'sensors_chipsets': [],
|
||||
'use_fahrenheit': True,
|
||||
'char_before_unit': ' '
|
||||
}
|
||||
}
|
||||
)
|
||||
def test_sensors_only_in_fahrenheit(self, _, __):
|
||||
def test_sensors_only_in_fahrenheit(self, _):
|
||||
"""Test computations around `sensors` output and Fahrenheit (naive) conversion"""
|
||||
self.assertDictEqual(
|
||||
Temperature().value,
|
||||
@ -249,15 +250,16 @@ class TestTemperatureEntry(unittest.TestCase):
|
||||
]
|
||||
)
|
||||
@patch('archey.entries.temperature.iglob')
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
side_effect=[
|
||||
{'sensors_chipsets': []},
|
||||
{'use_fahrenheit': False},
|
||||
{'char_before_unit': 'o'}
|
||||
]
|
||||
@HelperMethods.patch_clean_configuration(
|
||||
configuration={
|
||||
'temperature': {
|
||||
'sensors_chipsets': [],
|
||||
'use_fahrenheit': False,
|
||||
'char_before_unit': 'o'
|
||||
}
|
||||
}
|
||||
)
|
||||
def test_sensors_error_1(self, _, iglob_mock, ___):
|
||||
def test_sensors_error_1(self, iglob_mock, _):
|
||||
"""Test `sensors` (hard) failure handling and polling from files in Celsius"""
|
||||
iglob_mock.return_value = iter([file.name for file in self._temp_files])
|
||||
|
||||
@ -294,15 +296,16 @@ class TestTemperatureEntry(unittest.TestCase):
|
||||
]
|
||||
)
|
||||
@patch('archey.entries.temperature.iglob')
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
side_effect=[
|
||||
{'sensors_chipsets': []},
|
||||
{'use_fahrenheit': False},
|
||||
{'char_before_unit': 'o'}
|
||||
]
|
||||
@HelperMethods.patch_clean_configuration(
|
||||
configuration={
|
||||
'temperature': {
|
||||
'sensors_chipsets': [],
|
||||
'use_fahrenheit': False,
|
||||
'char_before_unit': 'o'
|
||||
}
|
||||
}
|
||||
)
|
||||
def test_sensors_error_2(self, _, iglob_mock, ___):
|
||||
def test_sensors_error_2(self, iglob_mock, _):
|
||||
"""Test `sensors` (hard) failure handling and polling from files in Celsius"""
|
||||
iglob_mock.return_value = iter([file.name for file in self._temp_files])
|
||||
self.assertDictEqual(
|
||||
@ -326,14 +329,8 @@ class TestTemperatureEntry(unittest.TestCase):
|
||||
'archey.entries.temperature.iglob',
|
||||
return_value=[] # No temperature from file will be retrieved.
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
side_effect=[
|
||||
{'sensors_chipsets': []}, # Needed key.
|
||||
{'not_detected': 'Not detected'} # Needed key.
|
||||
]
|
||||
)
|
||||
def test_celsius_to_fahrenheit_conversion(self, _, __, ___):
|
||||
@HelperMethods.patch_clean_configuration
|
||||
def test_celsius_to_fahrenheit_conversion(self, _, __):
|
||||
"""Simple tests for the `_convert_to_fahrenheit` static method"""
|
||||
test_conversion_cases = [
|
||||
(-273.15, -459.67),
|
@ -4,6 +4,8 @@ import unittest
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from archey.entries.terminal import Terminal
|
||||
from archey.test.entries import HelperMethods
|
||||
from archey.constants import DEFAULT_CONFIG
|
||||
|
||||
|
||||
class TestTerminalEntry(unittest.TestCase):
|
||||
@ -20,11 +22,8 @@ class TestTerminalEntry(unittest.TestCase):
|
||||
},
|
||||
clear=True
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
return_value={'use_unicode': False}
|
||||
)
|
||||
def test_terminal_emulator_term_program(self, _):
|
||||
@HelperMethods.patch_clean_configuration
|
||||
def test_terminal_emulator_term_program(self):
|
||||
"""Check that `TERM_PROGRAM` is honored even if `TERM` or `COLORTERM` is defined"""
|
||||
self.assertEqual(Terminal().value, 'A-COOL-TERMINAL-EMULATOR')
|
||||
|
||||
@ -36,11 +35,8 @@ class TestTerminalEntry(unittest.TestCase):
|
||||
},
|
||||
clear=True
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
return_value={'use_unicode': False}
|
||||
)
|
||||
def test_terminal_emulator_special_term(self, _):
|
||||
@HelperMethods.patch_clean_configuration
|
||||
def test_terminal_emulator_special_term(self):
|
||||
"""Check that `TERM` is honored even if a "known identifier" could be found"""
|
||||
self.assertEqual(Terminal().value, 'OH-A-SPECIAL-CASE')
|
||||
|
||||
@ -52,11 +48,8 @@ class TestTerminalEntry(unittest.TestCase):
|
||||
},
|
||||
clear=True
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
return_value={'use_unicode': False}
|
||||
)
|
||||
def test_terminal_emulator_name_normalization(self, _):
|
||||
@HelperMethods.patch_clean_configuration
|
||||
def test_terminal_emulator_name_normalization(self):
|
||||
"""Check that our manual terminal detection as long as name normalization are working"""
|
||||
self.assertEqual(Terminal().value, 'Konsole')
|
||||
|
||||
@ -65,11 +58,14 @@ class TestTerminalEntry(unittest.TestCase):
|
||||
{'TERM': 'xterm-256color'},
|
||||
clear=True
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
return_value={'use_unicode': True}
|
||||
@HelperMethods.patch_clean_configuration(
|
||||
configuration={
|
||||
'colors_palette': {
|
||||
'use_unicode': True
|
||||
}
|
||||
}
|
||||
)
|
||||
def test_terminal_emulator_term_fallback_and_unicode(self, _):
|
||||
def test_terminal_emulator_term_fallback_and_unicode(self):
|
||||
"""Check that `TERM` is honored if present, and Unicode support for the colors palette"""
|
||||
terminal = Terminal()
|
||||
|
||||
@ -90,11 +86,8 @@ class TestTerminalEntry(unittest.TestCase):
|
||||
{'COLORTERM': 'kmscon'},
|
||||
clear=True
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
return_value={'use_unicode': False}
|
||||
)
|
||||
def test_terminal_emulator_colorterm(self, _):
|
||||
@HelperMethods.patch_clean_configuration
|
||||
def test_terminal_emulator_colorterm(self):
|
||||
"""Check we can detect terminals using the `COLORTERM` environment variable."""
|
||||
self.assertEqual(Terminal().value, 'KMSCON')
|
||||
|
||||
@ -107,11 +100,8 @@ class TestTerminalEntry(unittest.TestCase):
|
||||
},
|
||||
clear=True
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
return_value={'use_unicode': False}
|
||||
)
|
||||
def test_terminal_emulator_colorterm_override(self, _):
|
||||
@HelperMethods.patch_clean_configuration
|
||||
def test_terminal_emulator_colorterm_override(self):
|
||||
"""
|
||||
Check we observe terminal using `COLORTERM` even if `TERM` or a "known identifier" is found.
|
||||
"""
|
||||
@ -122,14 +112,14 @@ class TestTerminalEntry(unittest.TestCase):
|
||||
{},
|
||||
clear=True
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
side_effect=[
|
||||
{'not_detected': 'Not detected'},
|
||||
{'use_unicode': False}
|
||||
]
|
||||
@HelperMethods.patch_clean_configuration(
|
||||
configuration={
|
||||
'colors_palette': {
|
||||
'use_unicode': False
|
||||
}
|
||||
}
|
||||
)
|
||||
def test_not_detected(self, _):
|
||||
def test_not_detected(self):
|
||||
"""Test terminal emulator (non-)detection, without Unicode support"""
|
||||
terminal = Terminal()
|
||||
|
||||
@ -138,7 +128,7 @@ class TestTerminalEntry(unittest.TestCase):
|
||||
output = output_mock.append.call_args[0][1]
|
||||
|
||||
self.assertIsNone(terminal.value)
|
||||
self.assertTrue(output.startswith('Not detected'))
|
||||
self.assertTrue(output.startswith(DEFAULT_CONFIG['default_strings']['not_detected']))
|
||||
self.assertFalse(output.count('\u2588'))
|
||||
|
||||
|
@ -6,6 +6,8 @@ import unittest
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from archey.entries.user import User
|
||||
from archey.test.entries import HelperMethods
|
||||
from archey.constants import DEFAULT_CONFIG
|
||||
|
||||
|
||||
class TestUserEntry(unittest.TestCase):
|
||||
@ -41,11 +43,8 @@ class TestUserEntry(unittest.TestCase):
|
||||
'archey.entries.user.check_output',
|
||||
side_effect=CalledProcessError(1, 'id', "id: ’1000’: no such user\n")
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
return_value={'not_detected': 'Not detected'}
|
||||
)
|
||||
def test_config_fall_back(self, _, __, ___):
|
||||
@HelperMethods.patch_clean_configuration
|
||||
def test_config_fall_back(self, _, __):
|
||||
"""`id` fails, but Archey must not !"""
|
||||
user = User()
|
||||
|
||||
@ -55,7 +54,7 @@ class TestUserEntry(unittest.TestCase):
|
||||
self.assertIsNone(user.value)
|
||||
self.assertEqual(
|
||||
output_mock.append.call_args[0][1],
|
||||
'Not detected'
|
||||
DEFAULT_CONFIG['default_strings']['not_detected']
|
||||
)
|
||||
|
||||
|
@ -9,6 +9,8 @@ from urllib.error import URLError
|
||||
|
||||
from archey.test import CustomAssertions
|
||||
from archey.entries.wan_ip import WanIp
|
||||
from archey.test.entries import HelperMethods
|
||||
from archey.constants import DEFAULT_CONFIG
|
||||
|
||||
class TestWanIpEntry(unittest.TestCase, CustomAssertions):
|
||||
"""
|
||||
@ -21,15 +23,14 @@ class TestWanIpEntry(unittest.TestCase, CustomAssertions):
|
||||
'0123::4567:89a:dead:beef\n'
|
||||
]
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
side_effect=[
|
||||
{'ipv4_detection': None}, # Needed key.
|
||||
{'wan_ip_v6_support': True},
|
||||
{'ipv6_detection': None} # Needed key.
|
||||
]
|
||||
@HelperMethods.patch_clean_configuration(
|
||||
configuration={
|
||||
'ip_settings': {
|
||||
'wan_ip_v6_support': True
|
||||
}
|
||||
}
|
||||
)
|
||||
def test_ipv6_and_ipv4(self, _, __):
|
||||
def test_ipv6_and_ipv4(self, _):
|
||||
"""Test the regular case : Both IPv4 and IPv6 are retrieved"""
|
||||
self.assertEqual(
|
||||
WanIp().value,
|
||||
@ -40,14 +41,14 @@ class TestWanIpEntry(unittest.TestCase, CustomAssertions):
|
||||
'archey.entries.wan_ip.check_output',
|
||||
return_value='XXX.YY.ZZ.TTT'
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
side_effect=[
|
||||
{'ipv4_detection': None}, # Needed key.
|
||||
{'wan_ip_v6_support': False}
|
||||
]
|
||||
@HelperMethods.patch_clean_configuration(
|
||||
configuration={
|
||||
'ip_settings': {
|
||||
'wan_ip_v6_support': False
|
||||
}
|
||||
}
|
||||
)
|
||||
def test_ipv4_only(self, _, __):
|
||||
def test_ipv4_only(self, _):
|
||||
"""Test only public IPv4 detection"""
|
||||
self.assertEqual(
|
||||
WanIp().value,
|
||||
@ -62,16 +63,14 @@ class TestWanIpEntry(unittest.TestCase, CustomAssertions):
|
||||
]
|
||||
)
|
||||
@patch('archey.entries.wan_ip.urlopen')
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
side_effect=[
|
||||
{'ipv4_detection': None}, # Needed key.
|
||||
{'wan_ip_v6_support': True},
|
||||
{'ipv6_detection': None}, # Needed key.
|
||||
{'ipv6_detection': None} # Needed key.
|
||||
]
|
||||
@HelperMethods.patch_clean_configuration(
|
||||
configuration={
|
||||
'ip_settings': {
|
||||
'wan_ip_v6_support': True
|
||||
}
|
||||
}
|
||||
)
|
||||
def test_ipv6_timeout(self, _, urlopen_mock, ___):
|
||||
def test_ipv6_timeout(self, urlopen_mock, _):
|
||||
"""
|
||||
Test when `dig` call timeout for the IPv6 detection.
|
||||
Additionally check the `output` method behavior.
|
||||
@ -100,15 +99,14 @@ class TestWanIpEntry(unittest.TestCase, CustomAssertions):
|
||||
'archey.entries.wan_ip.urlopen',
|
||||
side_effect=URLError('<urlopen error timed out>') # `urlopen` call will fail
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
side_effect=[
|
||||
{'ipv4_detection': None}, # Needed key.
|
||||
{'ipv4_detection': None}, # Needed key.
|
||||
{'wan_ip_v6_support': False}
|
||||
]
|
||||
@HelperMethods.patch_clean_configuration(
|
||||
configuration={
|
||||
'ip_settings': {
|
||||
'wan_ip_v6_support': False
|
||||
}
|
||||
}
|
||||
)
|
||||
def test_ipv4_timeout_twice(self, _, __, ___):
|
||||
def test_ipv4_timeout_twice(self, _, __):
|
||||
"""Test when both `dig` and `URLOpen` trigger timeouts..."""
|
||||
self.assertListEmpty(WanIp().value)
|
||||
|
||||
@ -120,15 +118,14 @@ class TestWanIpEntry(unittest.TestCase, CustomAssertions):
|
||||
'archey.entries.wan_ip.urlopen',
|
||||
side_effect=SocketTimeoutError(1) # `urlopen` call will fail
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
side_effect=[
|
||||
{'ipv4_detection': None}, # Needed key.
|
||||
{'ipv4_detection': None}, # Needed key.
|
||||
{'wan_ip_v6_support': False}
|
||||
]
|
||||
@HelperMethods.patch_clean_configuration(
|
||||
configuration={
|
||||
'ip_settings': {
|
||||
'wan_ip_v6_support': False
|
||||
}
|
||||
}
|
||||
)
|
||||
def test_ipv4_timeout_twice_socket_error(self, _, __, ___):
|
||||
def test_ipv4_timeout_twice_socket_error(self, _, __):
|
||||
"""Test when both `dig` timeouts and `URLOpen` raises `socket.timeout`..."""
|
||||
self.assertListEmpty(WanIp().value)
|
||||
|
||||
@ -140,15 +137,14 @@ class TestWanIpEntry(unittest.TestCase, CustomAssertions):
|
||||
'urllib.request.urlopen',
|
||||
return_value=None # No object will be returned
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
side_effect=[
|
||||
{'ipv4_detection': None}, # Needed key.
|
||||
{'wan_ip_v6_support': False},
|
||||
{'no_address': 'No Address'}
|
||||
]
|
||||
@HelperMethods.patch_clean_configuration(
|
||||
configuration={
|
||||
'ip_settings': {
|
||||
'wan_ip_v6_support': False
|
||||
}
|
||||
}
|
||||
)
|
||||
def test_no_address(self, _, __, ___):
|
||||
def test_no_address(self, _, __):
|
||||
"""
|
||||
Test when no address could be retrieved.
|
||||
Additionally check the `output` method behavior.
|
||||
@ -161,7 +157,7 @@ class TestWanIpEntry(unittest.TestCase, CustomAssertions):
|
||||
self.assertListEmpty(wan_ip.value)
|
||||
self.assertEqual(
|
||||
output_mock.append.call_args[0][1],
|
||||
'No Address'
|
||||
DEFAULT_CONFIG['default_strings']['no_address']
|
||||
)
|
||||
|
||||
|
@ -4,6 +4,8 @@ import unittest
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from archey.entries.window_manager import WindowManager
|
||||
from archey.test.entries import HelperMethods
|
||||
from archey.constants import DEFAULT_CONFIG
|
||||
|
||||
|
||||
class TestWindowManagerEntry(unittest.TestCase):
|
||||
@ -56,11 +58,8 @@ Window manager's "showing the desktop" mode: OFF
|
||||
'here'
|
||||
)
|
||||
)
|
||||
@patch(
|
||||
'archey.configuration.Configuration.get',
|
||||
return_value={'not_detected': 'Not detected'}
|
||||
)
|
||||
def test_no_wmctrl_mismatch(self, _, __):
|
||||
@HelperMethods.patch_clean_configuration
|
||||
def test_no_wmctrl_mismatch(self, _):
|
||||
"""Test (non-detection) when processes list do not contain any known value"""
|
||||
window_manager = WindowManager()
|
||||
|
||||
@ -70,7 +69,7 @@ Window manager's "showing the desktop" mode: OFF
|
||||
self.assertIsNone(window_manager.value)
|
||||
self.assertEqual(
|
||||
output_mock.append.call_args[0][1],
|
||||
'Not detected'
|
||||
DEFAULT_CONFIG['default_strings']['not_detected']
|
||||
)
|
||||
|
||||
|
@ -132,82 +132,78 @@ class TestConfigurationUtil(unittest.TestCase):
|
||||
)
|
||||
|
||||
def test_update_recursive(self):
|
||||
"""Test for the `_update_recursive` private method"""
|
||||
configuration = Configuration()
|
||||
with patch.dict(
|
||||
configuration._config, # pylint: disable=protected-access
|
||||
{
|
||||
'allow_overriding': True,
|
||||
'suppress_warnings': False,
|
||||
'default_strings': {
|
||||
'no_address': 'No Address',
|
||||
'not_detected': 'Not detected'
|
||||
},
|
||||
'colors_palette': {
|
||||
'use_unicode': False
|
||||
},
|
||||
'ip_settings': {
|
||||
'lan_ip_max_count': 2
|
||||
},
|
||||
'temperature': {
|
||||
'use_fahrenheit': False
|
||||
}
|
||||
},
|
||||
clear=True
|
||||
):
|
||||
# We change existing values, add new ones, and omit some others.
|
||||
configuration._update_recursive( # pylint: disable=protected-access
|
||||
configuration._config, # pylint: disable=protected-access
|
||||
{
|
||||
'suppress_warnings': True,
|
||||
'colors_palette': {
|
||||
'use_unicode': False
|
||||
},
|
||||
'default_strings': {
|
||||
'no_address': '\xde\xad \xbe\xef',
|
||||
'not_detected': 'Not detected',
|
||||
'virtual_environment': 'Virtual Environment'
|
||||
},
|
||||
'temperature': {
|
||||
'a_weird_new_dict': [
|
||||
None,
|
||||
'l33t',
|
||||
{
|
||||
'really': 'one_more_?'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
)
|
||||
"""Test for the `update_recursive` class method"""
|
||||
test_dict = {
|
||||
'allow_overriding': True,
|
||||
'suppress_warnings': False,
|
||||
'default_strings': {
|
||||
'no_address': 'No Address',
|
||||
'not_detected': 'Not detected'
|
||||
},
|
||||
'colors_palette': {
|
||||
'use_unicode': False
|
||||
},
|
||||
'ip_settings': {
|
||||
'lan_ip_max_count': 2
|
||||
},
|
||||
'temperature': {
|
||||
'use_fahrenheit': False
|
||||
}
|
||||
}
|
||||
|
||||
self.assertDictEqual(
|
||||
configuration._config, # pylint: disable=protected-access
|
||||
{
|
||||
'allow_overriding': True,
|
||||
'suppress_warnings': True,
|
||||
'colors_palette': {
|
||||
'use_unicode': False
|
||||
},
|
||||
'default_strings': {
|
||||
'no_address': '\xde\xad \xbe\xef',
|
||||
'not_detected': 'Not detected',
|
||||
'virtual_environment': 'Virtual Environment'
|
||||
},
|
||||
'ip_settings': {
|
||||
'lan_ip_max_count': 2
|
||||
},
|
||||
'temperature': {
|
||||
'use_fahrenheit': False,
|
||||
'a_weird_new_dict': [
|
||||
None,
|
||||
'l33t',
|
||||
{
|
||||
'really': 'one_more_?'
|
||||
}
|
||||
]
|
||||
}
|
||||
# We change existing values, add new ones, and omit some others.
|
||||
Configuration.update_recursive(
|
||||
test_dict,
|
||||
{
|
||||
'suppress_warnings': True,
|
||||
'colors_palette': {
|
||||
'use_unicode': False
|
||||
},
|
||||
'default_strings': {
|
||||
'no_address': '\xde\xad \xbe\xef',
|
||||
'not_detected': 'Not detected',
|
||||
'virtual_environment': 'Virtual Environment'
|
||||
},
|
||||
'temperature': {
|
||||
'a_weird_new_dict': [
|
||||
None,
|
||||
'l33t',
|
||||
{
|
||||
'really': 'one_more_?'
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
self.assertDictEqual(
|
||||
test_dict,
|
||||
{
|
||||
'allow_overriding': True,
|
||||
'suppress_warnings': True,
|
||||
'colors_palette': {
|
||||
'use_unicode': False
|
||||
},
|
||||
'default_strings': {
|
||||
'no_address': '\xde\xad \xbe\xef',
|
||||
'not_detected': 'Not detected',
|
||||
'virtual_environment': 'Virtual Environment'
|
||||
},
|
||||
'ip_settings': {
|
||||
'lan_ip_max_count': 2
|
||||
},
|
||||
'temperature': {
|
||||
'use_fahrenheit': False,
|
||||
'a_weird_new_dict': [
|
||||
None,
|
||||
'l33t',
|
||||
{
|
||||
'really': 'one_more_?'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
def test_instantiation_config_path(self):
|
||||
"""Test for configuration loading from specific user-defined path"""
|
||||
@ -242,6 +238,14 @@ class TestConfigurationUtil(unittest.TestCase):
|
||||
self.assertEqual(configuration.get('ip_settings')['lan_ip_max_count'], 4)
|
||||
self.assertTrue(configuration.get('temperature')['use_fahrenheit'])
|
||||
|
||||
def test__iter__(self):
|
||||
"""Very simple method checking our `__iter__` implementation"""
|
||||
configuration = Configuration()
|
||||
self.assertEqual(
|
||||
configuration._config, # pylint: disable=protected-access
|
||||
dict(configuration)
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
2
setup.py
2
setup.py
@ -16,7 +16,7 @@ setup(
|
||||
name='archey4',
|
||||
version=__version__.lstrip('v'),
|
||||
description='Archey is a simple system information tool written in Python',
|
||||
keywords='archey python3 linux system-information monitoring',
|
||||
keywords='archey python3 linux system-information monitoring screenshot',
|
||||
url='https://github.com/HorlogeSkynet/archey4',
|
||||
author='Samuel Forestier', # Not alone
|
||||
author_email='dev+archey@samuel.domains',
|
||||
|
Loading…
x
Reference in New Issue
Block a user