# flake8: noqa import os import re import pytest from clog import Logger from utils.common import LogLevel logger = Logger() class TestLoggingBasics: @pytest.mark.parametrize( "value, expected", [ (Logger(), Logger()), (logger, logger), (Logger(), logger), (logger, Logger()) ] ) def test_new_logger_instance(self, value, expected): assert value is expected def test_logger_file_default(self): assert logger.log == os.path.realpath("dump.log") def test_creation_of_new_logger(self): assert logger is not Logger.new() @pytest.mark.parametrize( "value, expected", [(".log", '.log'), (".dump.log", ".dump.log"), ("./non-dir/log", "dump.log"),] ) def test_using_different_log_file(self, value, expected): global logger logger = logger.new(out_f=value) os.remove(logger.log) assert Logger().log == os.path.realpath(expected).strip('"') class TestLoggingSTD: global logger logger = logger.new() @pytest.mark.parametrize( "value, expected, s, e", [ (*("Normal text to STDOUT",) * 2, None, None), (*("Normal test with a newline\nto STDOUT",) * 2, None, None), (("Text", "with", "hyphens"), "Text-with-hyphens", "-", None), ("Text here...", "Text here...\r", None, '\r') ] ) def test_message_written_to_stdout(self, value, expected, s, e, capture_stdpipe): if isinstance(value, tuple): logger.printLog(*value, level=LogLevel.NORMAL, sep=s, end=e) else: logger.printLog(value, level=LogLevel.NORMAL, sep=s, end=e) assert capture_stdpipe['stdout'].rstrip('\n') == expected and capture_stdpipe['stderr'] == "" @pytest.mark.parametrize( "value, expected, s, e", [ (*("Normal text to STDOUT",) * 2, None, None), (*("Normal test with a newline\nto STDOUT",) * 2, None, None), (("Text", "with", "hyphens"), "Text-with-hyphens", "-", None), ("Text here...", "Text here...\r", None, '\r') ] ) def test_message_written_to_stderr(self, value, expected, s, e, capture_stdpipe): if isinstance(value, tuple): logger.printLog(*value, level=LogLevel.DEBUG, sep=s, end=e) else: logger.printLog(value, level=LogLevel.DEBUG, sep=s, end=e) assert capture_stdpipe['stderr'].rstrip('\n') == expected and capture_stdpipe['stdout'] == "" def test_message_not_on_std_pipe(self, capture_stdpipe): with open(os.path.devnull, 'w') as devnull: Logger.printLog("Message isn't sent to STDOUT or STDERR", file=devnull) assert capture_stdpipe['stdout'] == "" and capture_stdpipe['stderr'] == "" @pytest.mark.skip def test_when_file_descriptor_redirect_is_given(self): ### :@Ethan: OK this test requires a little explaining as to what's going on # and why it's happening. Since this project was pulled out of another and # became standalone, the original program which made use of this system was # designed to prevent writes with ANSI escape sequences on PIPE when a file # descriptor redirect was given from the command-line. That logic still exists # and here we invoke that behavour for testing by running a bit of Python script # from the terminal. # # # :@UPDATE: if anyone knows how to test this behaviour by invoking that a TTY # is present in a subprocess call, create an Issue or a PR with the appropriate # code to get something like that working. I've spent way too much time on trying # to prove the system works and behaves how it should, but you can confirm this # happens by calling the `Logger.printLog()` method from an external script # and performing a file descriptor redirect to a file. If you don't see ASNI # escape sequences, the system works correctly, and you can call the module # again without redirect to ensure the terminal gets coloured output on log levels # `LogLevel.DEBUG` or higher. ... def test_print_log_does_not_handle_string_paths(self, capture_stdpipe): Logger.printLog("This fails correctly", file="bad_file.txt") assert capture_stdpipe['stderr'] != "" class TestLogging2File: def test_print_log_2_file_handles_string_paths(self, capture_stdpipe): Logger.printLog2File("Hello, World!", file=logger.log, mode='w') assert capture_stdpipe['stdout'] == "" and capture_stdpipe['stderr'] == "" def test_print_log_2_file_writes_to_file(self): Logger.printLog2File("Message to log", file=logger.log, mode='w') with open(logger.log, 'r') as f: assert re.match('^.*Message to log$', f.read()) class TestPseudoLogs: global logger logger = logger.new() @pytest.mark.parametrize( "value", [Logger().debug, Logger().warn, Logger().error] ) def test_pseudologs_are_instance_bound(self, value): assert hasattr(value, '__self__') @pytest.mark.parametrize( "value, ln, lv", [ (logger.debug, 1, "DEBUG"), (logger.warn, 2, "WARN"), (logger.error, 3, "ERROR"), ] ) def test_pseudologs_write_to_file(self, value, ln, lv): value("Pseudolog to file") with open(logger.log, 'r') as f: assert re.match(f'^.*{lv}\\s+Pseudolog to file$', f.readlines()[ln]) @pytest.mark.parametrize( "value, ln", [ (logger.debug, 4), (logger.warn, 5), (logger.error, 6), ] ) def test_pseudologs_write_to_file_and_console(self, value, ln, capture_stdpipe): value("Pseudolog to file and console", strace=False).withConsole() with open(logger.log, 'r') as f: assert re.match(f'^.*{capture_stdpipe["stderr"]}$', f.readlines()[ln])