예제 #1
0
    def test_format_to_json(self, print_mock, _, __):
        """Test how the `output` method handles JSON preferred formatting of entries"""
        output = Output(format_to_json=True)
        # We can't set the `name` attribute of a mock on its creation,
        # so this is a little bit messy...
        mocked_entries = [
            Mock(value='test'),
            Mock(value=0xDEAD)
        ]
        mocked_entries[0].name = 'test'
        mocked_entries[1].name = 'name'

        output._entries = mocked_entries  # pylint: disable=protected-access
        output.output()

        # Check that `print` output is properly formatted as JSON, with expected results.
        output_json_data = json.loads(print_mock.call_args[0][0])['data']
        self.assertEqual(
            output_json_data['test'],
            'test'
        )
        self.assertEqual(
            output_json_data['name'],
            0xDEAD
        )
예제 #2
0
    def test_line_wrapping(self, print_mock, termsize_mock, _, __):
        """Test how the `output` method handles wrapping lines that are too long"""
        output = Output()

        # We only need a column value for the terminal size
        termsize_tuple = namedtuple('termsize_tuple', 'columns')
        termsize_mock.return_value = termsize_tuple(10)

        output._results = [  # pylint: disable=protected-access
            'short',  # no truncation - too short
            'looooooong',  # truncation - too long
            'tenchars',  # no truncation - exactly the right width
            '\x1b[0;31mshort\x1b[0m',  # no truncation - too short
            '\x1b[0;31mlooooooong\x1b[0m'  # truncation - too long, long word truncated
        ]
        output.output()

        print_mock.assert_called_with("""\
W short
O \x1b[0m...
O tenchars
O \x1b[0;31mshort\x1b[0m
O \x1b[0;31m\x1b[0m...\x1b[0m\
""")
        # Check that `print` has been called only once.
        # `unittest.mock.Mock.assert_called_once` is not available against Python < 3.6.
        self.assertEqual(print_mock.call_count, 1)
예제 #3
0
    def test_line_wrapping(self, print_mock, termsize_mock, _, __, ___, ____):
        """Test how the `output` method handles wrapping lines that are too long"""
        output = Output()

        # We only need a column value for the terminal size
        termsize_tuple = namedtuple('termsize_tuple', 'columns')
        termsize_mock.return_value = termsize_tuple(13)

        output._results = [  # pylint: disable=protected-access
            'short',  # no truncation - too short
            'looooooong',  # truncation - too long
            'adjusted',  # no truncation - exactly the right width
            '\x1b[0;31mshort\x1b[0m',  # no truncation - too short
            '\x1b[0;31mlooooooong\x1b[0m'  # truncation - too long, long word truncated
        ]
        output.output()

        print_mock.assert_called_with("""\
W    short
O    \x1b[0m...
O    adjusted
O    \x1b[0;31mshort\x1b[0m
O    \x1b[0;31m\x1b[0m...\x1b[0m\
""")
        # Check that `print` has been called only once.
        self.assertTrue(print_mock.assert_called_once)
예제 #4
0
    def test_append_custom_entries_color(self, _, __):
        """Check that `Output` honor `ANSI_COLOR` as required"""
        output = Output()
        output.append("key", "value")

        self.assertListEqual(
            output._results,  # pylint: disable=protected-access
            [f"\x1b[5;31;47mkey:{Colors.CLEAR} value"])
예제 #5
0
    def test_append_regular(self, _, __):
        """Test the `append` method, for new entries"""
        output = Output()
        output.append('KEY', 'VALUE')

        self.assertListEqual(
            output._results,  # pylint: disable=protected-access
            ['COLOR_0KEY:{clear} VALUE'.format(clear=Colors.CLEAR)])
예제 #6
0
    def test_append(self):
        """Test the `append` method, for new entries"""
        output = Output()

        # Let's manually set the distribution for the test case...
        output.distribution = Distributions.DEBIAN

        output.append('KEY', 'VALUE')

        self.assertEqual(output.results, ['COLOR_1KEY:CLEAR VALUE'])
예제 #7
0
    def test_append_ansi_color(self, _, __):
        """Check that `Output` honor `ANSI_COLOR` as required"""
        output = Output()
        output.append("key", "value")

        # Slackware logo got three colors, so let's check they have been correctly replaced.
        self.assertTrue(
            all('ANSI_COLOR' in str(color) for color in output._colors)  # pylint: disable=protected-access
        )
        self.assertEqual(
            len(output._colors),  # pylint: disable=protected-access
            3  # Slackware's logo got 3 defined colors.
        )
        self.assertListEqual(
            output._results,  # pylint: disable=protected-access
            [f"\x1b[ANSI_COLORmkey:{Colors.CLEAR} value"])
예제 #8
0
    def test_init_windows_subsystem(self, _, __):
        """Test output for Windows Subsystem Linux"""
        output = Output()

        self.assertEqual(
            output.distribution,
            Distributions.WINDOWS
        )
예제 #9
0
    def test_init_unknown_distro(self, _, __):
        """Test unknown distribution output"""
        output = Output()

        self.assertEqual(
            output.distribution,
            Distributions.LINUX
        )
예제 #10
0
    def test_init_known_distro(self, _, __):
        """Test known distribution output"""
        output = Output()

        self.assertEqual(
            output.distribution,
            Distributions.DEBIAN
        )
예제 #11
0
    def test_init_distro_like_first(self, _, __, ___, ____):
        """Test distribution matching from the `os-release`'s `ID_LIKE` option (multiple entries)"""
        output = Output()

        self.assertEqual(
            output._distribution,  # pylint: disable=protected-access
            Distributions.LINUX_MINT
        )
예제 #12
0
    def test_init_distro_like(self, _, __, ___, ____):
        """Test distribution matching from the `os-release`'s `ID_LIKE` option"""
        output = Output()

        self.assertEqual(
            output._distribution,  # pylint: disable=protected-access
            Distributions.UBUNTU
        )
예제 #13
0
    def test_init_both_distro_calls_fail(self, _, __, ___, ____):
        """Test distribution fall-back when `distro` soft-fail two times"""
        output = Output()

        self.assertEqual(
            output._distribution,  # pylint: disable=protected-access
            Distributions.LINUX
        )
예제 #14
0
    def test_init_unknown_distro(self, _, __, ___, ____):
        """Test unknown distribution output"""
        output = Output()

        self.assertEqual(
            output._distribution,  # pylint: disable=protected-access
            Distributions.LINUX
        )
예제 #15
0
    def test_init_windows_subsystem(self, _, __):
        """Test output for Windows Subsystem Linux"""
        output = Output()

        self.assertEqual(
            output._distribution,  # pylint: disable=protected-access
            Distributions.WINDOWS
        )
예제 #16
0
    def test_init_distro_like_second(self, _, __, ___, ____):
        """Test distribution matching from the `os-release`'s `ID_LIKE` option (second candidate)"""
        output = Output()

        self.assertEqual(
            output._distribution,  # pylint: disable=protected-access
            Distributions.ARCH_LINUX
        )
예제 #17
0
    def test_preferred_distribution(self, _, run_detection_mock):
        """Simple test checking behavior when `preferred_distribution` is passed at instantiation"""
        output = Output(preferred_distribution='rhel')

        self.assertEqual(
            output._distribution,  # pylint: disable=protected-access
            Distributions.RED_HAT)
        # Check `Distributions.run_detection` method has not been called at all.
        self.assertFalse(run_detection_mock.called)
예제 #18
0
    def test_append_no_ansi_color(self, _, __):
        """Check that `Output` DOES NOT honor `ANSI_COLOR` when specified"""
        output = Output()
        output.append("key", "value")

        # Check that NO colors have been replaced (actually, that the list is the same as before).
        self.assertFalse(
            any('ANSI_COLOR' in str(color) for color in output._colors)  # pylint: disable=protected-access
        )
        self.assertListEqual(
            output._colors,  # pylint: disable=protected-access
            [  # Windows' colors palettes, unmodified.
                Colors.BLUE_BRIGHT, Colors.RED_BRIGHT, Colors.GREEN_BRIGHT,
                Colors.YELLOW_NORMAL
            ])
        self.assertListEqual(
            output._results,  # pylint: disable=protected-access
            [f"{Colors.BLUE_BRIGHT}key:{Colors.CLEAR} value"])
예제 #19
0
    def test_append_no_ansi_color(self, _, __, ___):
        """Check that `Output` DOES NOT honor `ANSI_COLOR` when specified"""
        output = Output()

        # Check that NO colors have been replaced (actually, that the list is the same as before).
        self.assertFalse(
            any('ANSI_COLOR' in str(color) for color in output._colors_palette)  # pylint: disable=protected-access
        )
        self.assertListEqual(
            output._colors_palette,  # pylint: disable=protected-access
            COLORS_DICT[Distributions.WINDOWS])
예제 #20
0
    def test_append_ansi_color(self, _, __, ___):
        """Check that `Output` honor `ANSI_COLOR` as required"""
        output = Output()

        # Slackware logo got three colors, so let's check they have been correctly replaced.
        self.assertTrue(
            all('ANSI_COLOR' in str(color) for color in output._colors_palette)  # pylint: disable=protected-access
        )
        self.assertEqual(
            len(output._colors_palette),  # pylint: disable=protected-access
            len(COLORS_DICT[Distributions.SLACKWARE]))
예제 #21
0
    def test_append_ansi_color(self, _, __, ___):
        """Check that `Output` honor `ANSI_COLOR` as required"""
        output = Output()

        # Slackware logo got three colors, so let's check they have been correctly replaced.
        self.assertTrue(
            all('ANSI_COLOR' in str(color) for color in output._colors)  # pylint: disable=protected-access
        )
        self.assertEqual(
            len(output._colors),  # pylint: disable=protected-access
            3  # Slackware's logo got 3 defined colors.
        )
예제 #22
0
def main():
    """Simple entry point"""

    # `Processes` is a singleton, let's populate the internal list here.
    Processes()

    # `Configuration` is a singleton, let's populate the internal object here.
    configuration = Configuration()

    output = Output()
    for entry in Entries:
        if configuration.get('entries', {}).get(entry.name, True):
            output.append(entry.name, entry.value().value)

    output.output()
예제 #23
0
def main():
    """Simple entry point"""
    args = args_parsing()

    # `Processes` is a singleton, let's populate the internal list here.
    Processes()

    # `Configuration` is a singleton, let's populate the internal object here.
    configuration = Configuration(config_path=args.config_path)

    # From configuration, gather the entries user-enabled.
    enabled_entries = [
        (entry.value, entry.name) for entry in Entries
        if configuration.get('entries', {}).get(entry.name, True)
    ]

    output = Output(preferred_distribution=args.distribution,
                    format_to_json=args.json)

    # We will map this function onto our enabled entries to instantiate them.
    def _entry_instantiator(entry_tuple):
        return entry_tuple[0](name=entry_tuple[1])

    # Let's use a context manager stack to manage conditional use of `TheadPoolExecutor`.
    with ExitStack() as cm_stack:
        if not configuration.get('parallel_loading'):
            mapper = map
        else:
            # Instantiate a threads pool to load our enabled entries in parallel.
            # We use threads (and not processes) since most work done by our entries is IO-bound.
            # `max_workers` is manually computed to mimic Python 3.8+ behaviour, but for our needs.
            #   See <https://github.com/python/cpython/pull/13618>.
            executor = cm_stack.enter_context(
                ThreadPoolExecutor(max_workers=min(
                    len(enabled_entries) or 1, (os.cpu_count() or 1) + 4)))
            mapper = executor.map

        for entry_instance in mapper(_entry_instantiator, enabled_entries):
            output.add_entry(entry_instance)

    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))
예제 #24
0
def main():
    """Simple entry point"""
    parser = argparse.ArgumentParser(prog='archey')
    parser.add_argument('-v',
                        '--version',
                        action='version',
                        version=__version__)
    parser.parse_args()

    # `Processes` is a singleton, let's populate the internal list here.
    Processes()

    # `Configuration` is a singleton, let's populate the internal object here.
    configuration = Configuration()

    output = Output()
    for entry in Entries:
        if configuration.get('entries', {}).get(entry.name, True):
            output.append(entry.name, entry.value().value)

    output.output()
예제 #25
0
    def test_centered_output(self, print_mock, _, __):
        """Test how the `output` method handles centering operations"""
        output = Output()

        # # ODD ENTRIES NUMBER # #
        # Entries smaller than logo
        output._results = [  # pylint: disable=protected-access
            '1', '2', '3'
        ]
        # Let's run the algorithm !
        output.output()
        self.assertListEqual(
            output._results,  # pylint: disable=protected-access
            [
                '', '', '', '', '', '', '', '1', '2', '3', '', '', '', '', '',
                '', '', ''
            ])

        # Entries bigger than logo
        output._results = [  # pylint: disable=protected-access
            '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12',
            '13', '14', '15', '16', '17', '18', '19', '20', '21'
        ]
        output.output()
        print_mock.assert_called_with("""\
FAKE_COLOR 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
FAKE_COLOR 20
FAKE_COLOR 21\x1b[0m\
""")

        # # EVEN ENTRIES NUMBER # #
        # Entries smaller than logo
        output._results = [  # pylint: disable=protected-access
            '1', '2', '3', '4'
        ]
        output.output()
        self.assertListEqual(
            output._results,  # pylint: disable=protected-access
            [
                '', '', '', '', '', '', '', '1', '2', '3', '4', '', '', '', '',
                '', '', ''
            ])

        # Entries bigger than logo
        output._results = [  # pylint: disable=protected-access
            '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12',
            '13', '14', '15', '16', '17', '18', '19', '20', '21', '22'
        ]
        output.output()
        print_mock.assert_called_with("""\
FAKE_COLOR 1
FAKE_COLOR 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
FAKE_COLOR 21
FAKE_COLOR 22\x1b[0m\
""")

        # # FULL ENTRIES # #
        output._results = [  # pylint: disable=protected-access
            '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12',
            '13', '14', '15', '16', '17', '18'
        ]
        output.output()
        self.assertListEqual(
            output._results,  # pylint: disable=protected-access
            [
                '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12',
                '13', '14', '15', '16', '17', '18'
            ])

        # # NO ENTRY # #
        output._results = []  # pylint: disable=protected-access
        output.output()
        self.assertListEqual(
            output._results,  # pylint: disable=protected-access
            [
                '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
                '', ''
            ])
예제 #26
0
    def test_centered_output(self, _):
        """Test how the `output` method handle centering operations"""
        output = Output()

        # Let's manually set the distribution for the test case...
        output.distribution = Distributions.DEBIAN

        # # ODD ENTRIES NUMBER # #
        output.results = [
            '1',
            '2',
            '3'
        ]
        # Let's run the algorithm !
        output.output()
        self.assertListEqual(
            output.results,
            [
                '', '', '', '', '', '', '',
                '1', '2', '3',
                '', '', '', '', '', '', '', ''
            ]
        )

        # # EVEN ENTRIES NUMBER # #
        output.results = [
            '1',
            '2',
            '3',
            '4'
        ]
        output.output()
        self.assertListEqual(
            output.results,
            [
                '', '', '', '', '', '', '',
                '1', '2', '3', '4',
                '', '', '', '', '', '', ''
            ]
        )

        # # FULL ENTRIES # #
        output.results = [
            '1', '2', '3', '4', '5', '6',
            '7', '8', '9', '10', '11', '12',
            '13', '14', '15', '16', '17', '18'
        ]
        output.output()
        self.assertListEqual(
            output.results,
            [
                '1', '2', '3', '4', '5', '6',
                '7', '8', '9', '10', '11', '12',
                '13', '14', '15', '16', '17', '18'
            ]
        )

        # # NO ENTRY # #
        output.results = []
        output.output()
        self.assertListEqual(
            output.results,
            [
                '', '', '', '', '', '',
                '', '', '', '', '', '',
                '', '', '', '', '', '',
            ]
        )
예제 #27
0
    def test_centered_output(self, _, __, ___, ____):
        """Test how the `output` method handles centering operations"""
        output = Output()

        # # ODD ENTRIES NUMBER # #
        output._results = [  # pylint: disable=protected-access
            '1',
            '2',
            '3'
        ]
        # Let's run the algorithm !
        output.output()
        self.assertListEqual(
            output._results,  # pylint: disable=protected-access
            [
                '', '', '', '', '', '', '',
                '1', '2', '3',
                '', '', '', '', '', '', '', ''
            ]
        )

        # # EVEN ENTRIES NUMBER # #
        output._results = [  # pylint: disable=protected-access
            '1',
            '2',
            '3',
            '4'
        ]
        output.output()
        self.assertListEqual(
            output._results,  # pylint: disable=protected-access
            [
                '', '', '', '', '', '', '',
                '1', '2', '3', '4',
                '', '', '', '', '', '', ''
            ]
        )

        # # FULL ENTRIES # #
        output._results = [  # pylint: disable=protected-access
            '1', '2', '3', '4', '5', '6',
            '7', '8', '9', '10', '11', '12',
            '13', '14', '15', '16', '17', '18'
        ]
        output.output()
        self.assertListEqual(
            output._results,  # pylint: disable=protected-access
            [
                '1', '2', '3', '4', '5', '6',
                '7', '8', '9', '10', '11', '12',
                '13', '14', '15', '16', '17', '18'
            ]
        )

        # # NO ENTRY # #
        output._results = []  # pylint: disable=protected-access
        output.output()
        self.assertListEqual(
            output._results,  # pylint: disable=protected-access
            [
                '', '', '', '', '', '',
                '', '', '', '', '', '',
                '', '', '', '', '', '',
            ]
        )
예제 #28
0
    def test_centered_output(self, print_mock, _, __, ___):
        """Test how the `output` method handles centering operations"""
        output = Output()

        with self.subTest(
                'Odd number of entries (entries smaller than logo).'):
            output._results = [  # pylint: disable=protected-access
                '1', '2', '3'
            ]
            output.output()
            self.assertListEqual(
                output._results,  # pylint: disable=protected-access
                [
                    '', '', '', '', '', '', '', '1', '2', '3', '', '', '', '',
                    '', '', '', ''
                ])

        with self.subTest('Odd number of entries (entries bigger than logo).'):
            output._results = [  # pylint: disable=protected-access
                '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12',
                '13', '14', '15', '16', '17', '18', '19', '20', '21'
            ]
            output.output()
            print_mock.assert_called_with("""\
FAKE_COLOR    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
FAKE_COLOR    20
FAKE_COLOR    21\x1b[0m\
""")

        output = Output()

        with self.subTest(
                'Even number of entries (entries smaller than logo).'):
            output._results = [  # pylint: disable=protected-access
                '1', '2', '3', '4'
            ]
            output.output()
            self.assertListEqual(
                output._results,  # pylint: disable=protected-access
                [
                    '', '', '', '', '', '', '', '1', '2', '3', '4', '', '', '',
                    '', '', '', ''
                ])

        with self.subTest(
                'Even number of entries (entries bigger than logo).'):
            output._results = [  # pylint: disable=protected-access
                '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12',
                '13', '14', '15', '16', '17', '18', '19', '20', '21', '22'
            ]
            output.output()
            print_mock.assert_called_with("""\
FAKE_COLOR    1
FAKE_COLOR    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
FAKE_COLOR    21
FAKE_COLOR    22\x1b[0m\
""")

        output = Output()

        with self.subTest('Full entries.'):
            output._results = [  # pylint: disable=protected-access
                '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12',
                '13', '14', '15', '16', '17', '18'
            ]
            output.output()
            self.assertListEqual(
                output._results,  # pylint: disable=protected-access
                [
                    '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11',
                    '12', '13', '14', '15', '16', '17', '18'
                ])

        output = Output()

        with self.subTest('No entry.'):
            output._results = []  # pylint: disable=protected-access
            output.output()
            self.assertListEqual(
                output._results,  # pylint: disable=protected-access
                [
                    '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
                    '', '', ''
                ])
예제 #29
0
def main():
    """Simple entry point"""
    args = args_parsing()

    # Setup logging.
    logging.basicConfig(format='%(levelname)s: %(message)s')

    # Populate our internal singletons once and for all.
    Processes()
    Environment()
    configuration = Configuration(config_path=args.config_path)

    # From configuration, gather the entries user-configured.
    available_entries = configuration.get('entries')
    if available_entries is None:
        # If none were specified, lazy-mimic a full-enabled entries list without any configuration.
        available_entries = [{'type': entry_name} for entry_name in Entries.__members__.keys()]

    output = Output(
        preferred_logo_style=args.logo_style,
        preferred_distribution=args.distribution,
        format_to_json=args.json
    )

    # We will map this function onto our enabled entries to instantiate them.
    def _entry_instantiator(entry: dict) -> Optional[Entry]:
        # Based on **required** `type` field, instantiate the corresponding `Entry` object.
        try:
            return Entries[entry.pop('type')].value(
                name=entry.pop('name', None),  # `name` is fully-optional.
                options=entry                  # Remaining fields should be propagated as options.
            )
        except KeyError as key_error:
            logging.warning(
                'One entry (misses or) uses an invalid `type` field (%s).', key_error
            )
            return None

    # Let's use a context manager stack to manage conditional use of `TheadPoolExecutor`.
    with ExitStack() as cm_stack:
        if not configuration.get('parallel_loading'):
            mapper = map
        else:
            # Instantiate a threads pool to load our enabled entries in parallel.
            # We use threads (and not processes) since most work done by our entries is IO-bound.
            # `max_workers` is manually computed to mimic Python 3.8+ behaviour, but for our needs.
            #   See <https://github.com/python/cpython/pull/13618>.
            executor = cm_stack.enter_context(ThreadPoolExecutor(
                max_workers=min(len(available_entries) or 1, (os.cpu_count() or 1) + 4)
            ))
            mapper = executor.map

        for entry_instance in mapper(_entry_instantiator, available_entries):
            if not entry_instance:
                continue

            output.add_entry(entry_instance)

    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.
        try:
            screenshot_taken = take_screenshot((args.screenshot or None))
        except KeyboardInterrupt:
            screenshot_taken = False
            print()
        finally:
            sys.exit((not screenshot_taken))