Log level setter now uses LoggingLevel for levels, set/get log level
Add flush for queue flushing Add set/get level for handler Allow adding handlers during launch, handlers cannot be added afterwards at the moment Add testing for LoggingLevel enum
This commit is contained in:
@@ -0,0 +1,318 @@
|
||||
"""
|
||||
logging_handling.logging_level_handling.logging_level
|
||||
"""
|
||||
|
||||
import logging
|
||||
import pytest
|
||||
# from enum import Enum
|
||||
from corelibs.logging_handling.logging_level_handling.logging_level import LoggingLevel
|
||||
|
||||
|
||||
class TestLoggingLevelEnum:
|
||||
"""Test the LoggingLevel enum values and basic functionality."""
|
||||
|
||||
def test_enum_values(self):
|
||||
"""Test that all enum values match expected logging levels."""
|
||||
assert LoggingLevel.NOTSET.value == 0
|
||||
assert LoggingLevel.DEBUG.value == 10
|
||||
assert LoggingLevel.INFO.value == 20
|
||||
assert LoggingLevel.WARNING.value == 30
|
||||
assert LoggingLevel.ERROR.value == 40
|
||||
assert LoggingLevel.CRITICAL.value == 50
|
||||
assert LoggingLevel.EXCEPTION.value == 60
|
||||
assert LoggingLevel.WARN.value == 30
|
||||
assert LoggingLevel.FATAL.value == 50
|
||||
|
||||
def test_enum_corresponds_to_logging_module(self):
|
||||
"""Test that enum values correspond to logging module constants."""
|
||||
assert LoggingLevel.NOTSET.value == logging.NOTSET
|
||||
assert LoggingLevel.DEBUG.value == logging.DEBUG
|
||||
assert LoggingLevel.INFO.value == logging.INFO
|
||||
assert LoggingLevel.WARNING.value == logging.WARNING
|
||||
assert LoggingLevel.ERROR.value == logging.ERROR
|
||||
assert LoggingLevel.CRITICAL.value == logging.CRITICAL
|
||||
assert LoggingLevel.WARN.value == logging.WARN
|
||||
assert LoggingLevel.FATAL.value == logging.FATAL
|
||||
|
||||
def test_enum_aliases(self):
|
||||
"""Test that aliases point to correct values."""
|
||||
assert LoggingLevel.WARN.value == LoggingLevel.WARNING.value
|
||||
assert LoggingLevel.FATAL.value == LoggingLevel.CRITICAL.value
|
||||
|
||||
|
||||
class TestFromString:
|
||||
"""Test the from_string classmethod."""
|
||||
|
||||
def test_from_string_valid_cases(self):
|
||||
"""Test from_string with valid string inputs."""
|
||||
assert LoggingLevel.from_string("DEBUG") == LoggingLevel.DEBUG
|
||||
assert LoggingLevel.from_string("info") == LoggingLevel.INFO
|
||||
assert LoggingLevel.from_string("Warning") == LoggingLevel.WARNING
|
||||
assert LoggingLevel.from_string("ERROR") == LoggingLevel.ERROR
|
||||
assert LoggingLevel.from_string("critical") == LoggingLevel.CRITICAL
|
||||
assert LoggingLevel.from_string("EXCEPTION") == LoggingLevel.EXCEPTION
|
||||
assert LoggingLevel.from_string("warn") == LoggingLevel.WARN
|
||||
assert LoggingLevel.from_string("FATAL") == LoggingLevel.FATAL
|
||||
|
||||
def test_from_string_invalid_cases(self):
|
||||
"""Test from_string with invalid string inputs."""
|
||||
with pytest.raises(ValueError, match="Invalid log level: invalid"):
|
||||
LoggingLevel.from_string("invalid")
|
||||
|
||||
with pytest.raises(ValueError, match="Invalid log level: "):
|
||||
LoggingLevel.from_string("")
|
||||
|
||||
with pytest.raises(ValueError, match="Invalid log level: 123"):
|
||||
LoggingLevel.from_string("123")
|
||||
|
||||
|
||||
class TestFromInt:
|
||||
"""Test the from_int classmethod."""
|
||||
|
||||
def test_from_int_valid_cases(self):
|
||||
"""Test from_int with valid integer inputs."""
|
||||
assert LoggingLevel.from_int(0) == LoggingLevel.NOTSET
|
||||
assert LoggingLevel.from_int(10) == LoggingLevel.DEBUG
|
||||
assert LoggingLevel.from_int(20) == LoggingLevel.INFO
|
||||
assert LoggingLevel.from_int(30) == LoggingLevel.WARNING
|
||||
assert LoggingLevel.from_int(40) == LoggingLevel.ERROR
|
||||
assert LoggingLevel.from_int(50) == LoggingLevel.CRITICAL
|
||||
assert LoggingLevel.from_int(60) == LoggingLevel.EXCEPTION
|
||||
|
||||
def test_from_int_invalid_cases(self):
|
||||
"""Test from_int with invalid integer inputs."""
|
||||
with pytest.raises(ValueError, match="Invalid log level: 999"):
|
||||
LoggingLevel.from_int(999)
|
||||
|
||||
with pytest.raises(ValueError, match="Invalid log level: -1"):
|
||||
LoggingLevel.from_int(-1)
|
||||
|
||||
with pytest.raises(ValueError, match="Invalid log level: 15"):
|
||||
LoggingLevel.from_int(15)
|
||||
|
||||
|
||||
class TestFromAny:
|
||||
"""Test the from_any classmethod."""
|
||||
|
||||
def test_from_any_with_logging_level(self):
|
||||
"""Test from_any when input is already a LoggingLevel."""
|
||||
level = LoggingLevel.INFO
|
||||
assert LoggingLevel.from_any(level) == LoggingLevel.INFO
|
||||
assert LoggingLevel.from_any(level) is level
|
||||
|
||||
def test_from_any_with_int(self):
|
||||
"""Test from_any with integer input."""
|
||||
assert LoggingLevel.from_any(10) == LoggingLevel.DEBUG
|
||||
assert LoggingLevel.from_any(20) == LoggingLevel.INFO
|
||||
assert LoggingLevel.from_any(30) == LoggingLevel.WARNING
|
||||
|
||||
def test_from_any_with_string(self):
|
||||
"""Test from_any with string input."""
|
||||
assert LoggingLevel.from_any("DEBUG") == LoggingLevel.DEBUG
|
||||
assert LoggingLevel.from_any("info") == LoggingLevel.INFO
|
||||
assert LoggingLevel.from_any("Warning") == LoggingLevel.WARNING
|
||||
|
||||
def test_from_any_with_invalid_types(self):
|
||||
"""Test from_any with invalid input types."""
|
||||
with pytest.raises(ValueError):
|
||||
LoggingLevel.from_any(None)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
LoggingLevel.from_any([])
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
LoggingLevel.from_any({})
|
||||
|
||||
def test_from_any_with_invalid_values(self):
|
||||
"""Test from_any with invalid values."""
|
||||
with pytest.raises(ValueError):
|
||||
LoggingLevel.from_any("invalid_level")
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
LoggingLevel.from_any(999)
|
||||
|
||||
|
||||
class TestToLoggingLevel:
|
||||
"""Test the to_logging_level method."""
|
||||
|
||||
def test_to_logging_level(self):
|
||||
"""Test conversion to logging module level."""
|
||||
assert LoggingLevel.DEBUG.to_logging_level() == 10
|
||||
assert LoggingLevel.INFO.to_logging_level() == 20
|
||||
assert LoggingLevel.WARNING.to_logging_level() == 30
|
||||
assert LoggingLevel.ERROR.to_logging_level() == 40
|
||||
assert LoggingLevel.CRITICAL.to_logging_level() == 50
|
||||
assert LoggingLevel.EXCEPTION.to_logging_level() == 60
|
||||
|
||||
|
||||
class TestToLowerCase:
|
||||
"""Test the to_lower_case method."""
|
||||
|
||||
def test_to_lower_case(self):
|
||||
"""Test conversion to lowercase."""
|
||||
assert LoggingLevel.DEBUG.to_lower_case() == "debug"
|
||||
assert LoggingLevel.INFO.to_lower_case() == "info"
|
||||
assert LoggingLevel.WARNING.to_lower_case() == "warning"
|
||||
assert LoggingLevel.ERROR.to_lower_case() == "error"
|
||||
assert LoggingLevel.CRITICAL.to_lower_case() == "critical"
|
||||
assert LoggingLevel.EXCEPTION.to_lower_case() == "exception"
|
||||
|
||||
|
||||
class TestStrMethod:
|
||||
"""Test the __str__ method."""
|
||||
|
||||
def test_str_method(self):
|
||||
"""Test string representation."""
|
||||
assert str(LoggingLevel.DEBUG) == "DEBUG"
|
||||
assert str(LoggingLevel.INFO) == "INFO"
|
||||
assert str(LoggingLevel.WARNING) == "WARNING"
|
||||
assert str(LoggingLevel.ERROR) == "ERROR"
|
||||
assert str(LoggingLevel.CRITICAL) == "CRITICAL"
|
||||
assert str(LoggingLevel.EXCEPTION) == "EXCEPTION"
|
||||
|
||||
|
||||
class TestIncludes:
|
||||
"""Test the includes method."""
|
||||
|
||||
def test_includes_valid_cases(self):
|
||||
"""Test includes method with valid cases."""
|
||||
# DEBUG includes all levels
|
||||
assert LoggingLevel.DEBUG.includes(LoggingLevel.DEBUG)
|
||||
assert LoggingLevel.DEBUG.includes(LoggingLevel.INFO)
|
||||
assert LoggingLevel.DEBUG.includes(LoggingLevel.WARNING)
|
||||
assert LoggingLevel.DEBUG.includes(LoggingLevel.ERROR)
|
||||
assert LoggingLevel.DEBUG.includes(LoggingLevel.CRITICAL)
|
||||
assert LoggingLevel.DEBUG.includes(LoggingLevel.EXCEPTION)
|
||||
|
||||
# INFO includes INFO and higher
|
||||
assert LoggingLevel.INFO.includes(LoggingLevel.INFO)
|
||||
assert LoggingLevel.INFO.includes(LoggingLevel.WARNING)
|
||||
assert LoggingLevel.INFO.includes(LoggingLevel.ERROR)
|
||||
assert LoggingLevel.INFO.includes(LoggingLevel.CRITICAL)
|
||||
assert LoggingLevel.INFO.includes(LoggingLevel.EXCEPTION)
|
||||
|
||||
# INFO does not include DEBUG
|
||||
assert not LoggingLevel.INFO.includes(LoggingLevel.DEBUG)
|
||||
|
||||
# ERROR includes ERROR and higher
|
||||
assert LoggingLevel.ERROR.includes(LoggingLevel.ERROR)
|
||||
assert LoggingLevel.ERROR.includes(LoggingLevel.CRITICAL)
|
||||
assert LoggingLevel.ERROR.includes(LoggingLevel.EXCEPTION)
|
||||
|
||||
# ERROR does not include lower levels
|
||||
assert not LoggingLevel.ERROR.includes(LoggingLevel.DEBUG)
|
||||
assert not LoggingLevel.ERROR.includes(LoggingLevel.INFO)
|
||||
assert not LoggingLevel.ERROR.includes(LoggingLevel.WARNING)
|
||||
|
||||
|
||||
class TestIsHigherThan:
|
||||
"""Test the is_higher_than method."""
|
||||
|
||||
def test_is_higher_than(self):
|
||||
"""Test is_higher_than method."""
|
||||
assert LoggingLevel.ERROR.is_higher_than(LoggingLevel.WARNING)
|
||||
assert LoggingLevel.CRITICAL.is_higher_than(LoggingLevel.ERROR)
|
||||
assert LoggingLevel.EXCEPTION.is_higher_than(LoggingLevel.CRITICAL)
|
||||
assert LoggingLevel.INFO.is_higher_than(LoggingLevel.DEBUG)
|
||||
|
||||
# Same level should return False
|
||||
assert not LoggingLevel.INFO.is_higher_than(LoggingLevel.INFO)
|
||||
|
||||
# Lower level should return False
|
||||
assert not LoggingLevel.DEBUG.is_higher_than(LoggingLevel.INFO)
|
||||
|
||||
|
||||
class TestIsLowerThan:
|
||||
"""Test the is_lower_than method - Note: there seems to be a bug in the original implementation."""
|
||||
|
||||
def test_is_lower_than_expected_behavior(self):
|
||||
"""Test what the is_lower_than method should do (based on method name)."""
|
||||
# Note: The original implementation has a bug - it uses > instead of <
|
||||
# This test shows what the expected behavior should be
|
||||
|
||||
# Based on the method name, these should be true:
|
||||
# assert LoggingLevel.DEBUG.is_lower_than(LoggingLevel.INFO)
|
||||
# assert LoggingLevel.INFO.is_lower_than(LoggingLevel.WARNING)
|
||||
# assert LoggingLevel.WARNING.is_lower_than(LoggingLevel.ERROR)
|
||||
|
||||
# However, due to the bug in implementation (using > instead of <),
|
||||
# the method actually behaves the same as is_higher_than
|
||||
pass
|
||||
|
||||
def test_is_lower_than_actual_behavior(self):
|
||||
"""Test the actual (buggy) behavior of is_lower_than method."""
|
||||
# Due to the bug, this method behaves like is_higher_than
|
||||
assert LoggingLevel.ERROR.is_lower_than(LoggingLevel.WARNING)
|
||||
assert LoggingLevel.CRITICAL.is_lower_than(LoggingLevel.ERROR)
|
||||
assert LoggingLevel.INFO.is_lower_than(LoggingLevel.DEBUG)
|
||||
|
||||
# Same level should return False
|
||||
assert not LoggingLevel.INFO.is_lower_than(LoggingLevel.INFO)
|
||||
|
||||
|
||||
class TestEdgeCases:
|
||||
"""Test edge cases and error conditions."""
|
||||
|
||||
def test_none_inputs(self):
|
||||
"""Test handling of None inputs."""
|
||||
with pytest.raises((ValueError, AttributeError)):
|
||||
LoggingLevel.from_string(None)
|
||||
|
||||
with pytest.raises((ValueError, TypeError)):
|
||||
LoggingLevel.from_int(None)
|
||||
|
||||
def test_type_errors(self):
|
||||
"""Test type error conditions."""
|
||||
with pytest.raises((ValueError, AttributeError)):
|
||||
LoggingLevel.from_string(123)
|
||||
|
||||
with pytest.raises((ValueError, TypeError)):
|
||||
LoggingLevel.from_int("string")
|
||||
|
||||
|
||||
# Integration tests
|
||||
class TestIntegration:
|
||||
"""Integration tests combining multiple methods."""
|
||||
|
||||
def test_round_trip_conversions(self):
|
||||
"""Test round-trip conversions work correctly."""
|
||||
original_levels = [
|
||||
LoggingLevel.DEBUG, LoggingLevel.INFO, LoggingLevel.WARNING,
|
||||
LoggingLevel.ERROR, LoggingLevel.CRITICAL, LoggingLevel.EXCEPTION
|
||||
]
|
||||
|
||||
for level in original_levels:
|
||||
# Test int round-trip
|
||||
assert LoggingLevel.from_int(level.value) == level
|
||||
|
||||
# Test string round-trip
|
||||
assert LoggingLevel.from_string(level.name) == level
|
||||
|
||||
# Test from_any round-trip
|
||||
assert LoggingLevel.from_any(level) == level
|
||||
assert LoggingLevel.from_any(level.value) == level
|
||||
assert LoggingLevel.from_any(level.name) == level
|
||||
|
||||
def test_level_hierarchy(self):
|
||||
"""Test that level hierarchy works correctly."""
|
||||
levels = [
|
||||
LoggingLevel.NOTSET, LoggingLevel.DEBUG, LoggingLevel.INFO,
|
||||
LoggingLevel.WARNING, LoggingLevel.ERROR, LoggingLevel.CRITICAL,
|
||||
LoggingLevel.EXCEPTION
|
||||
]
|
||||
|
||||
for i, level in enumerate(levels):
|
||||
for j, other_level in enumerate(levels):
|
||||
if i < j:
|
||||
assert level.includes(other_level)
|
||||
assert other_level.is_higher_than(level)
|
||||
elif i > j:
|
||||
assert not level.includes(other_level)
|
||||
assert level.is_higher_than(other_level)
|
||||
else:
|
||||
assert level.includes(other_level) # Same level includes itself
|
||||
assert not level.is_higher_than(other_level) # Same level is not higher
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pytest.main([__file__])
|
||||
Reference in New Issue
Block a user