This is an automated email from the ASF dual-hosted git repository. swebb2066 pushed a commit to branch logger_is_enabled_test_overhead in repository https://gitbox.apache.org/repos/asf/logging-log4cxx.git
commit 68351c06bb47b7a247cd487a4a0c30421cc4adc7 Author: Stephen Webb <[email protected]> AuthorDate: Mon Feb 23 17:41:53 2026 +1100 Reduce that overhead of Logger::isXxxxxEnabled() methods --- src/main/cpp/logger.cpp | 29 +- src/main/include/log4cxx/logger.h | 17 + src/test/cpp/CMakeLists.txt | 1 + src/test/cpp/loggerthresholdtests.cpp | 2452 +++++++++++++++++++++++++++++++++ src/test/cpp/logunit.h | 1 + 5 files changed, 2494 insertions(+), 6 deletions(-) diff --git a/src/main/cpp/logger.cpp b/src/main/cpp/logger.cpp index 491a0f01..f42dbf16 100644 --- a/src/main/cpp/logger.cpp +++ b/src/main/cpp/logger.cpp @@ -401,6 +401,21 @@ bool Logger::isAttached(const AppenderPtr appender) const return m_priv->aai.isAttached(appender); } +bool Logger::isThresholdEqualTo(const LevelPtr& level) const +{ + return level->toInt() == m_threshold; +} + +bool Logger::isThresholdEqualTo(const LoggerPtr& other) const +{ + return other->m_threshold == m_threshold; +} + +bool Logger::isThresholdValid() const +{ + return getEffectiveLevel()->toInt() == m_threshold; +} + bool Logger::isTraceEnabled() const { auto rep = getHierarchy(); @@ -410,7 +425,7 @@ bool Logger::isTraceEnabled() const return false; } - return getEffectiveLevel()->toInt() <= Level::TRACE_INT; + return m_threshold <= Level::TRACE_INT; } bool Logger::isDebugEnabled() const @@ -422,7 +437,7 @@ bool Logger::isDebugEnabled() const return false; } - return getEffectiveLevel()->toInt() <= Level::DEBUG_INT; + return m_threshold <= Level::DEBUG_INT; } bool Logger::isEnabledFor(const LevelPtr& level1) const @@ -447,7 +462,7 @@ bool Logger::isInfoEnabled() const return false; } - return getEffectiveLevel()->toInt() <= Level::INFO_INT; + return m_threshold <= Level::INFO_INT; } bool Logger::isErrorEnabled() const @@ -459,7 +474,7 @@ bool Logger::isErrorEnabled() const return false; } - return getEffectiveLevel()->toInt() <= Level::ERROR_INT; + return m_threshold <= Level::ERROR_INT; } bool Logger::isWarnEnabled() const @@ -471,7 +486,7 @@ bool Logger::isWarnEnabled() const return false; } - return getEffectiveLevel()->toInt() <= Level::WARN_INT; + return m_threshold <= Level::WARN_INT; } bool Logger::isFatalEnabled() const @@ -483,7 +498,7 @@ bool Logger::isFatalEnabled() const return false; } - return getEffectiveLevel()->toInt() <= Level::FATAL_INT; + return m_threshold <= Level::FATAL_INT; } /*void Logger::l7dlog(const LevelPtr& level, const String& key, @@ -640,6 +655,8 @@ void Logger::setParent(LoggerPtr parentLogger) { m_priv->parent = parentLogger; updateThreshold(); + if (auto rep = dynamic_cast<Hierarchy*>(getHierarchy())) + rep->updateChildren(this); } void Logger::setLevel(const LevelPtr level1) diff --git a/src/main/include/log4cxx/logger.h b/src/main/include/log4cxx/logger.h index 4078615d..20de3faa 100644 --- a/src/main/include/log4cxx/logger.h +++ b/src/main/include/log4cxx/logger.h @@ -25,6 +25,7 @@ #include <log4cxx/helpers/resourcebundle.h> #include <log4cxx/helpers/asyncbuffer.h> #include <log4cxx/helpers/messagebuffer.h> +class LoggerThresholdConsistencyTest; namespace LOG4CXX_NS { @@ -1876,6 +1877,7 @@ class LOG4CXX_EXPORT Logger protected: friend class Hierarchy; + /** Only the Hierarchy class can remove the hierarchy of a logger. */ @@ -1893,6 +1895,21 @@ class LOG4CXX_EXPORT Logger */ void updateThreshold(); + protected: // Unit testing support methods + friend class LoggerThresholdConsistencyTest; + + /** Is m_threshold the same as level->toInt() + */ + bool isThresholdEqualTo(const LevelPtr& level) const; + + /** Is m_threshold the same as \c other + */ + bool isThresholdEqualTo(const LoggerPtr& other) const; + + /** Is m_threshold the same as getEffectiveLevel()->toInt() + */ + bool isThresholdValid() const; + private: spi::LoggerRepository* getHierarchy() const; diff --git a/src/test/cpp/CMakeLists.txt b/src/test/cpp/CMakeLists.txt index a3126e53..33d132f4 100644 --- a/src/test/cpp/CMakeLists.txt +++ b/src/test/cpp/CMakeLists.txt @@ -60,6 +60,7 @@ set(ALL_LOG4CXX_TESTS leveltestcase levelchangetestcase loggertestcase + loggerthresholdtests mdctestcase minimumtestcase ndctestcase diff --git a/src/test/cpp/loggerthresholdtests.cpp b/src/test/cpp/loggerthresholdtests.cpp new file mode 100644 index 00000000..8b72ef97 --- /dev/null +++ b/src/test/cpp/loggerthresholdtests.cpp @@ -0,0 +1,2452 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <log4cxx/logger.h> +#include <log4cxx/hierarchy.h> +#include <log4cxx/level.h> +#include "logunit.h" +#if LOG4CXX_ABI_VERSION <= 15 +#include <log4cxx/defaultloggerfactory.h> +#else +#include <log4cxx/spi/loggerfactory.h> +#endif + +/**** +This comprehensive test suite verifies that Logger::m_threshold always equals Logger::getEffectiveLevel()->toInt(). + +Basic Scenarios (Tests 1-6) +• Root logger initialization +• Single logger level setting +• Simple inheritance +• Two-level hierarchies with inheritance and overrides + +Multi-Level Hierarchies (Tests 7-10) +• Three and four-level hierarchies +• Various override patterns (middle, leaf, mixed) + +Dynamic Parent Changes (Tests 11-13) +• Setting parent from null +• Changing parents +• Multiple parent reassignments + +Level Propagation (Tests 14-16) +• Root level changes propagating to children +• Parent changes propagating to grandchildren +• Verification that overridden children don't change + +Complex Hierarchies (Tests 17-19) +• Mixed level configurations +• Sibling independence +• Deep hierarchies (7+ levels) + +Null Level Handling (Tests 20-22) +• Setting level to null and inheritance +• Toggling between null and values +• Null levels with parent changes + +Edge Cases (Tests 23-25) +• All standard levels (OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL) +• Rapid level changes +• Interleaved parent and child changes + +Creation Order (Tests 26-28) +• Child created before parent +• Provision node scenarios +• Out-of-order creation + +Advanced Scenarios (Tests 29-50) +• Multiple children before parent +• Complex interleaved creation +• Wide hierarchies (many siblings) +• Deep hierarchies with alternating overrides +• Same parent reassignment +• Root affecting entire hierarchy +• Mixed null and non-null levels +• Multiple parent changes with verification +• Grandchildren before ancestors +• Stress tests with many changes +• Different name patterns +• All-null chains except root + +Concurrent Branches (Tests 41-50) +• Multiple independent branches +• Cross-branch changes +• Extremely deep hierarchies (50 levels) +• Logger retrieval consistency +• Factory-created loggers + +Special Patterns (Tests 51-65) +• Parent-child swaps +• All same level +• Rapid reassignments +• Zigzag patterns +• Level removal and re-addition +• Diamond hierarchies +• Very long names +• Same level multiple times +• Complex mixed operations +• Empty and single-character names +• Final comprehensive stress test + +***/ + +using namespace log4cxx; + +LOGUNIT_CLASS(LoggerThresholdConsistencyTest) +{ + LOGUNIT_TEST_SUITE(LoggerThresholdConsistencyTest); + + // Basic hierarchy tests + LOGUNIT_TEST(testRootLoggerInitialState); + LOGUNIT_TEST(testSingleLoggerSetLevel); + LOGUNIT_TEST(testSingleLoggerInheritsFromRoot); + + // Simple parent-child tests + LOGUNIT_TEST(testTwoLevelHierarchyChildInherits); + LOGUNIT_TEST(testTwoLevelHierarchyChildOverrides); + LOGUNIT_TEST(testTwoLevelHierarchyParentChanges); + + // Multi-level hierarchy tests + LOGUNIT_TEST(testThreeLevelHierarchyAllInherit); + LOGUNIT_TEST(testThreeLevelHierarchyMiddleOverrides); + LOGUNIT_TEST(testThreeLevelHierarchyLeafOverrides); + LOGUNIT_TEST(testFourLevelHierarchyMixedOverrides); + + // Dynamic parent change tests + LOGUNIT_TEST(testSetParentFromNullToValid); + LOGUNIT_TEST(testSetParentChangeParent); + LOGUNIT_TEST(testSetParentMultipleTimes); + + // Level change propagation tests + LOGUNIT_TEST(testRootLevelChangePropagatesToChildren); + LOGUNIT_TEST(testParentLevelChangePropagatesToGrandchildren); + LOGUNIT_TEST(testLevelChangeDoesNotPropagateToOverriddenChildren); + + // Complex hierarchy tests + LOGUNIT_TEST(testComplexHierarchyWithMixedLevels); + LOGUNIT_TEST(testSiblingLoggersIndependent); + LOGUNIT_TEST(testDeepHierarchyInheritance); + + // Level set to null tests + LOGUNIT_TEST(testSetLevelToNullInheritsFromParent); + LOGUNIT_TEST(testSetLevelToNullThenBackToValue); + LOGUNIT_TEST(testChildSetToNullAfterParentChange); + + // Edge cases + LOGUNIT_TEST(testAllStandardLevels); + LOGUNIT_TEST(testRapidLevelChanges); + LOGUNIT_TEST(testParentAndChildLevelChangesInterleaved); + + // Hierarchy reorganization tests + LOGUNIT_TEST(testLoggerCreationOrderDoesNotMatter); + LOGUNIT_TEST(testChildCreatedBeforeParent); + LOGUNIT_TEST(testProvisionNodeScenario); + + // Additional miscellaneous tests + LOGUNIT_TEST(testMultipleChildrenBeforeParent); + LOGUNIT_TEST(testComplexInterleavedCreationAndLevelSetting); + LOGUNIT_TEST(testWideHierarchy); + LOGUNIT_TEST(testDeepHierarchyAlternatingOverrides); + LOGUNIT_TEST(testSetParentToSameParent); + LOGUNIT_TEST(testRootLoggerAffectsEntireHierarchy); + LOGUNIT_TEST(testMixedNullAndNonNullLevels); + LOGUNIT_TEST(testThresholdAfterMultipleParentChanges); + LOGUNIT_TEST(testGrandchildBeforeParentAndMiddle); + LOGUNIT_TEST(testStressTestManyLevelChanges); + LOGUNIT_TEST(testDifferentNamePatterns); + LOGUNIT_TEST(testParentChainAllNullExceptRoot); + LOGUNIT_TEST(testConcurrentHierarchyBranches); + LOGUNIT_TEST(testSetLevelOnLoggerWithExistingChildren); + LOGUNIT_TEST(testAlternatingSetLevelAndSetParent); + LOGUNIT_TEST(testOffAndAllLevels); + LOGUNIT_TEST(testComplexProvisionNodeScenario); + LOGUNIT_TEST(testMultipleSiblingsWithDifferentLevels); + LOGUNIT_TEST(testParentChainWithGaps); + LOGUNIT_TEST(testThresholdAfterHierarchyOperations); + LOGUNIT_TEST(testCrossBranchHierarchyChanges); + LOGUNIT_TEST(testExtremelyDeepHierarchy); + LOGUNIT_TEST(testThresholdConsistencyDuringRetrieval); + LOGUNIT_TEST(testThresholdConsistencyWithLoggerFactory); + LOGUNIT_TEST(testThresholdAfterParentChildSwap); + LOGUNIT_TEST(testThresholdWithAllSameLevel); + LOGUNIT_TEST(testThresholdAfterRapidParentReassignments); + LOGUNIT_TEST(testThresholdWithZigzagLevelPattern); + LOGUNIT_TEST(testThresholdAfterRemovingAndReaddingLevels); + LOGUNIT_TEST(testThresholdWithDiamondHierarchy); + LOGUNIT_TEST(testThresholdWithVeryLongLoggerNames); + LOGUNIT_TEST(testThresholdAfterSettingSameLevelMultipleTimes); + LOGUNIT_TEST(testComplexMixedOperations); + LOGUNIT_TEST(testThresholdAfterParentChangeWithGrandchildren); + LOGUNIT_TEST(testThresholdWithEmptyLoggerName); + LOGUNIT_TEST(testThresholdWithSingleCharacterNames); + LOGUNIT_TEST(testFinalComprehensiveStressTest); + + LOGUNIT_TEST_SUITE_END(); + +private: + HierarchyPtr hierarchy; + +public: + void setUp() override + { + hierarchy = Hierarchy::create(); + } + + void tearDown() override + { + hierarchy->resetConfiguration(); + hierarchy.reset(); + } + + void assertThresholdConsistent(const LoggerPtr& logger) + { + LOGUNIT_ASSERT_MESSAGE(logger->isThresholdValid() + , LOG4CXX_STR("threshold does not match getEffectiveLevel()->toInt() for logger: " + logger->getName()) + ); + } + + void assertThresholdIs(const LevelPtr& level, const LoggerPtr& logger) + { + LOGUNIT_ASSERT_MESSAGE(logger->isThresholdEqualTo(level) + , LOG4CXX_STR("threshold is not ") + level->toString() + LOG4CXX_STR(" for logger: " + logger->getName()) + ); + } + + void assertThresholdIs(const LoggerPtr& other, const LoggerPtr& logger) + { + LOGUNIT_ASSERT_MESSAGE(logger->isThresholdEqualTo(other) + , LOG4CXX_STR("threshold is not the same as ") + other->getName() + LOG4CXX_STR(" for logger: " + logger->getName()) + ); + } + +public: + // Test 1: Root logger initial state + void testRootLoggerInitialState() + { + LoggerPtr root = hierarchy->getRootLogger(); + assertThresholdConsistent(root); + } + + // Test 2: Single logger set level + void testSingleLoggerSetLevel() + { + LoggerPtr logger = hierarchy->getLogger("com.example"); + assertThresholdConsistent(logger); + + logger->setLevel(Level::getInfo()); + assertThresholdConsistent(logger); + + logger->setLevel(Level::getDebug()); + assertThresholdConsistent(logger); + + logger->setLevel(Level::getError()); + assertThresholdConsistent(logger); + } + + // Test 3: Single logger inherits from root + void testSingleLoggerInheritsFromRoot() + { + LoggerPtr root = hierarchy->getRootLogger(); + LoggerPtr logger = hierarchy->getLogger("com.example"); + + root->setLevel(Level::getWarn()); + assertThresholdConsistent(logger); + + root->setLevel(Level::getTrace()); + assertThresholdConsistent(logger); + } + + // Test 4: Two-level hierarchy - child inherits + void testTwoLevelHierarchyChildInherits() + { + LoggerPtr parent = hierarchy->getLogger("com"); + LoggerPtr child = hierarchy->getLogger("com.example"); + + parent->setLevel(Level::getInfo()); + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + + parent->setLevel(Level::getError()); + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + } + + // Test 5: Two-level hierarchy - child overrides + void testTwoLevelHierarchyChildOverrides() + { + LoggerPtr parent = hierarchy->getLogger("com"); + LoggerPtr child = hierarchy->getLogger("com.example"); + + parent->setLevel(Level::getWarn()); + child->setLevel(Level::getDebug()); + + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + + assertThresholdIs(Level::getWarn(), parent); + assertThresholdIs(Level::getDebug(), child); + } + + // Test 6: Two-level hierarchy - parent changes after child override + void testTwoLevelHierarchyParentChanges() + { + LoggerPtr parent = hierarchy->getLogger("com"); + LoggerPtr child = hierarchy->getLogger("com.example"); + + parent->setLevel(Level::getWarn()); + child->setLevel(Level::getDebug()); + + // Change parent - child should maintain its override + parent->setLevel(Level::getError()); + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + + assertThresholdIs(Level::getDebug(), child); + } + + // Test 7: Three-level hierarchy - all inherit + void testThreeLevelHierarchyAllInherit() + { + LoggerPtr root = hierarchy->getRootLogger(); + LoggerPtr level1 = hierarchy->getLogger("com"); + LoggerPtr level2 = hierarchy->getLogger("com.example"); + LoggerPtr level3 = hierarchy->getLogger("com.example.app"); + + root->setLevel(Level::getInfo()); + assertThresholdConsistent(root); + assertThresholdConsistent(level1); + assertThresholdConsistent(level2); + assertThresholdConsistent(level3); + } + + // Test 8: Three-level hierarchy - middle overrides + void testThreeLevelHierarchyMiddleOverrides() + { + LoggerPtr root = hierarchy->getRootLogger(); + LoggerPtr level1 = hierarchy->getLogger("com"); + LoggerPtr level2 = hierarchy->getLogger("com.example"); + LoggerPtr level3 = hierarchy->getLogger("com.example.app"); + + root->setLevel(Level::getError()); + level2->setLevel(Level::getDebug()); + + assertThresholdConsistent(root); + assertThresholdConsistent(level1); + assertThresholdConsistent(level2); + assertThresholdConsistent(level3); + + assertThresholdIs(Level::getError(), level1); + assertThresholdIs(Level::getDebug(), level2); + assertThresholdIs(Level::getDebug(), level3); + } + + // Test 9: Three-level hierarchy - leaf overrides + void testThreeLevelHierarchyLeafOverrides() + { + LoggerPtr root = hierarchy->getRootLogger(); + LoggerPtr level1 = hierarchy->getLogger("com"); + LoggerPtr level2 = hierarchy->getLogger("com.example"); + LoggerPtr level3 = hierarchy->getLogger("com.example.app"); + + root->setLevel(Level::getWarn()); + level3->setLevel(Level::getTrace()); + + assertThresholdConsistent(root); + assertThresholdConsistent(level1); + assertThresholdConsistent(level2); + assertThresholdConsistent(level3); + + assertThresholdIs(Level::getWarn(), level1); + assertThresholdIs(Level::getWarn(), level2); + assertThresholdIs(Level::getTrace(), level3); + } + + // Test 10: Four-level hierarchy - mixed overrides + void testFourLevelHierarchyMixedOverrides() + { + LoggerPtr root = hierarchy->getRootLogger(); + LoggerPtr level1 = hierarchy->getLogger("org"); + LoggerPtr level2 = hierarchy->getLogger("org.apache"); + LoggerPtr level3 = hierarchy->getLogger("org.apache.log4cxx"); + LoggerPtr level4 = hierarchy->getLogger("org.apache.log4cxx.test"); + + root->setLevel(Level::getError()); + level2->setLevel(Level::getInfo()); + level4->setLevel(Level::getDebug()); + + assertThresholdConsistent(root); + assertThresholdConsistent(level1); + assertThresholdConsistent(level2); + assertThresholdConsistent(level3); + assertThresholdConsistent(level4); + + assertThresholdIs(Level::getError(), level1); + assertThresholdIs(Level::getInfo(), level2); + assertThresholdIs(Level::getInfo(), level3); + assertThresholdIs(Level::getDebug(), level4); + } + + // Test 11: Set parent from null to valid + void testSetParentFromNullToValid() + { + LoggerPtr parent = hierarchy->getLogger("parent"); + LoggerPtr child = hierarchy->getLogger("child"); + + parent->setLevel(Level::getWarn()); + child->setParent(parent); + + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + } + + // Test 12: Change parent + void testSetParentChangeParent() + { + LoggerPtr parent1 = hierarchy->getLogger("parent1"); + LoggerPtr parent2 = hierarchy->getLogger("parent2"); + LoggerPtr child = hierarchy->getLogger("child"); + + parent1->setLevel(Level::getDebug()); + parent2->setLevel(Level::getError()); + + child->setParent(parent1); + assertThresholdConsistent(child); + assertThresholdIs(Level::getDebug(), child); + + child->setParent(parent2); + assertThresholdConsistent(child); + assertThresholdIs(Level::getError(), child); + } + + // Test 13: Set parent multiple times + void testSetParentMultipleTimes() + { + LoggerPtr root = hierarchy->getRootLogger(); + LoggerPtr parent1 = hierarchy->getLogger("p1"); + LoggerPtr parent2 = hierarchy->getLogger("p2"); + LoggerPtr child = hierarchy->getLogger("child"); + + root->setLevel(Level::getFatal()); + parent1->setLevel(Level::getInfo()); + parent2->setLevel(Level::getDebug()); + + child->setParent(root); + assertThresholdConsistent(child); + + child->setParent(parent1); + assertThresholdConsistent(child); + + child->setParent(parent2); + assertThresholdConsistent(child); + + child->setParent(root); + assertThresholdConsistent(child); + } + + // Test 14: Root level change propagates to children + void testRootLevelChangePropagatesToChildren() + { + LoggerPtr root = hierarchy->getRootLogger(); + LoggerPtr child1 = hierarchy->getLogger("child1"); + LoggerPtr child2 = hierarchy->getLogger("child2"); + LoggerPtr grandchild = hierarchy->getLogger("child1.grandchild"); + + root->setLevel(Level::getWarn()); + assertThresholdConsistent(child1); + assertThresholdConsistent(child2); + assertThresholdConsistent(grandchild); + + root->setLevel(Level::getDebug()); + assertThresholdConsistent(child1); + assertThresholdConsistent(child2); + assertThresholdConsistent(grandchild); + } + + // Test 15: Parent level change propagates to grandchildren + void testParentLevelChangePropagatesToGrandchildren() + { + LoggerPtr root = hierarchy->getRootLogger(); + LoggerPtr parent = hierarchy->getLogger("parent"); + LoggerPtr child = hierarchy->getLogger("parent.child"); + LoggerPtr grandchild = hierarchy->getLogger("parent.child.grandchild"); + + root->setLevel(Level::getError()); + parent->setLevel(Level::getInfo()); + + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + assertThresholdConsistent(grandchild); + + parent->setLevel(Level::getDebug()); + assertThresholdIs(Level::getDebug(), grandchild); + } + + // Test 16: Level change does not propagate to overridden children + void testLevelChangeDoesNotPropagateToOverriddenChildren() + { + LoggerPtr root = hierarchy->getRootLogger(); + LoggerPtr parent = hierarchy->getLogger("parent"); + LoggerPtr child = hierarchy->getLogger("parent.child"); + LoggerPtr grandchild = hierarchy->getLogger("parent.child.grandchild"); + + root->setLevel(Level::getError()); + parent->setLevel(Level::getInfo()); + child->setLevel(Level::getDebug()); + + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + assertThresholdConsistent(grandchild); + + // Change parent level + parent->setLevel(Level::getWarn()); + + // Child should keep its own level + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + assertThresholdConsistent(grandchild); + + assertThresholdIs(Level::getWarn(), parent); + assertThresholdIs(Level::getDebug(), child); + assertThresholdIs(Level::getDebug(), grandchild); + } + + // Test 17: Complex hierarchy with mixed levels + void testComplexHierarchyWithMixedLevels() + { + LoggerPtr root = hierarchy->getRootLogger(); + LoggerPtr a = hierarchy->getLogger("a"); + LoggerPtr ab = hierarchy->getLogger("a.b"); + LoggerPtr abc = hierarchy->getLogger("a.b.c"); + LoggerPtr abcd = hierarchy->getLogger("a.b.c.d"); + LoggerPtr ax = hierarchy->getLogger("a.x"); + LoggerPtr axy = hierarchy->getLogger("a.x.y"); + + root->setLevel(Level::getFatal()); + a->setLevel(Level::getError()); + abc->setLevel(Level::getDebug()); + ax->setLevel(Level::getInfo()); + + assertThresholdConsistent(root); + assertThresholdConsistent(a); + assertThresholdConsistent(ab); + assertThresholdConsistent(abc); + assertThresholdConsistent(abcd); + assertThresholdConsistent(ax); + assertThresholdConsistent(axy); + + assertThresholdIs(Level::getFatal(), root); + assertThresholdIs(Level::getError(), a); + assertThresholdIs(Level::getError(), ab); + assertThresholdIs(Level::getDebug(), abc); + assertThresholdIs(Level::getDebug(), abcd); + assertThresholdIs(Level::getInfo(), ax); + assertThresholdIs(Level::getInfo(), axy); + } + + // Test 18: Sibling loggers are independent + void testSiblingLoggersIndependent() + { + LoggerPtr root = hierarchy->getRootLogger(); + LoggerPtr sibling1 = hierarchy->getLogger("com.example.app1"); + LoggerPtr sibling2 = hierarchy->getLogger("com.example.app2"); + LoggerPtr sibling3 = hierarchy->getLogger("com.example.app3"); + + root->setLevel(Level::getWarn()); + sibling1->setLevel(Level::getDebug()); + sibling2->setLevel(Level::getError()); + // sibling3 inherits + + assertThresholdConsistent(sibling1); + assertThresholdConsistent(sibling2); + assertThresholdConsistent(sibling3); + + assertThresholdIs(Level::getDebug(), sibling1); + assertThresholdIs(Level::getError(), sibling2); + assertThresholdIs(Level::getWarn(), sibling3); + + // Change sibling1 - should not affect others + sibling1->setLevel(Level::getTrace()); + assertThresholdConsistent(sibling1); + assertThresholdConsistent(sibling2); + assertThresholdConsistent(sibling3); + + assertThresholdIs(Level::getTrace(), sibling1); + assertThresholdIs(Level::getError(), sibling2); + assertThresholdIs(Level::getWarn(), sibling3); + } + + // Test 19: Deep hierarchy inheritance + void testDeepHierarchyInheritance() + { + LoggerPtr root = hierarchy->getRootLogger(); + LoggerPtr l1 = hierarchy->getLogger("a"); + LoggerPtr l2 = hierarchy->getLogger("a.b"); + LoggerPtr l3 = hierarchy->getLogger("a.b.c"); + LoggerPtr l4 = hierarchy->getLogger("a.b.c.d"); + LoggerPtr l5 = hierarchy->getLogger("a.b.c.d.e"); + LoggerPtr l6 = hierarchy->getLogger("a.b.c.d.e.f"); + LoggerPtr l7 = hierarchy->getLogger("a.b.c.d.e.f.g"); + + root->setLevel(Level::getInfo()); + + assertThresholdConsistent(root); + assertThresholdConsistent(l1); + assertThresholdConsistent(l2); + assertThresholdConsistent(l3); + assertThresholdConsistent(l4); + assertThresholdConsistent(l5); + assertThresholdConsistent(l6); + assertThresholdConsistent(l7); + + // All should inherit INFO + assertThresholdIs(Level::getInfo(), l1); + assertThresholdIs(Level::getInfo(), l7); + + // Set middle level + l4->setLevel(Level::getDebug()); + assertThresholdConsistent(l1); + assertThresholdConsistent(l2); + assertThresholdConsistent(l3); + assertThresholdConsistent(l4); + assertThresholdConsistent(l5); + assertThresholdConsistent(l6); + assertThresholdConsistent(l7); + + assertThresholdIs(Level::getInfo(), l3); + assertThresholdIs(Level::getDebug(), l4); + assertThresholdIs(Level::getDebug(), l5); + assertThresholdIs(Level::getDebug(), l7); + } + + // Test 20: Set level to null - inherits from parent + void testSetLevelToNullInheritsFromParent() + { + LoggerPtr parent = hierarchy->getLogger("parent"); + LoggerPtr child = hierarchy->getLogger("parent.child"); + + parent->setLevel(Level::getWarn()); + child->setLevel(Level::getDebug()); + + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + assertThresholdIs(Level::getDebug(), child); + + // Set child level to null - should inherit from parent + child->setLevel(LevelPtr()); + assertThresholdConsistent(child); + assertThresholdIs(Level::getWarn(), child); + } + + // Test 21: Set level to null then back to value + void testSetLevelToNullThenBackToValue() + { + LoggerPtr parent = hierarchy->getLogger("parent"); + LoggerPtr child = hierarchy->getLogger("parent.child"); + + parent->setLevel(Level::getError()); + child->setLevel(Level::getInfo()); + assertThresholdConsistent(child); + assertThresholdIs(Level::getInfo(), child); + + child->setLevel(LevelPtr()); + assertThresholdConsistent(child); + assertThresholdIs(Level::getError(), child); + + child->setLevel(Level::getDebug()); + assertThresholdConsistent(child); + assertThresholdIs(Level::getDebug(), child); + + child->setLevel(LevelPtr()); + assertThresholdConsistent(child); + assertThresholdIs(Level::getError(), child); + } + + // Test 22: Child set to null after parent change + void testChildSetToNullAfterParentChange() + { + LoggerPtr parent = hierarchy->getLogger("parent"); + LoggerPtr child = hierarchy->getLogger("parent.child"); + + parent->setLevel(Level::getInfo()); + child->setLevel(Level::getDebug()); + + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + + // Set child to null + child->setLevel(LevelPtr()); + assertThresholdConsistent(child); + assertThresholdIs(Level::getInfo(), child); + + // Change parent level - child should follow + parent->setLevel(Level::getWarn()); + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + assertThresholdIs(Level::getWarn(), child); + + parent->setLevel(Level::getTrace()); + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + assertThresholdIs(Level::getTrace(), child); + } + + // Test 23: All standard levels + void testAllStandardLevels() + { + LoggerPtr logger = hierarchy->getLogger("test"); + + LevelPtr levels[] = { + Level::getOff(), + Level::getFatal(), + Level::getError(), + Level::getWarn(), + Level::getInfo(), + Level::getDebug(), + Level::getTrace(), + Level::getAll() + }; + + for (size_t i = 0; i < sizeof(levels)/sizeof(levels[0]); ++i) + { + logger->setLevel(levels[i]); + assertThresholdConsistent(logger); + assertThresholdIs(levels[i], logger); + } + } + + // Test 24: Rapid level changes + void testRapidLevelChanges() + { + LoggerPtr logger = hierarchy->getLogger("rapid"); + + for (int i = 0; i < 100; ++i) + { + logger->setLevel(Level::getDebug()); + assertThresholdConsistent(logger); + + logger->setLevel(Level::getInfo()); + assertThresholdConsistent(logger); + + logger->setLevel(Level::getWarn()); + assertThresholdConsistent(logger); + + logger->setLevel(Level::getError()); + assertThresholdConsistent(logger); + + logger->setLevel(LevelPtr()); + assertThresholdConsistent(logger); + } + } + + // Test 25: Parent and child level changes interleaved + void testParentAndChildLevelChangesInterleaved() + { + LoggerPtr parent = hierarchy->getLogger("parent"); + LoggerPtr child = hierarchy->getLogger("parent.child"); + LoggerPtr grandchild = hierarchy->getLogger("parent.child.grandchild"); + + parent->setLevel(Level::getInfo()); + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + assertThresholdConsistent(grandchild); + + child->setLevel(Level::getDebug()); + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + assertThresholdConsistent(grandchild); + + parent->setLevel(Level::getWarn()); + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + assertThresholdConsistent(grandchild); + + grandchild->setLevel(Level::getTrace()); + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + assertThresholdConsistent(grandchild); + + child->setLevel(LevelPtr()); + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + assertThresholdConsistent(grandchild); + + assertThresholdIs(Level::getWarn(), parent); + assertThresholdIs(Level::getWarn(), child); + assertThresholdIs(Level::getTrace(), grandchild); + + parent->setLevel(Level::getError()); + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + assertThresholdConsistent(grandchild); + + assertThresholdIs(Level::getError(), child); + assertThresholdIs(Level::getTrace(), grandchild); + } + + // Test 26: Logger creation order does not matter + void testLoggerCreationOrderDoesNotMatter() + { + // Create in hierarchical order + LoggerPtr a1 = hierarchy->getLogger("order1"); + LoggerPtr b1 = hierarchy->getLogger("order1.child"); + LoggerPtr c1 = hierarchy->getLogger("order1.child.grandchild"); + + a1->setLevel(Level::getWarn()); + assertThresholdConsistent(a1); + assertThresholdConsistent(b1); + assertThresholdConsistent(c1); + + // Create in reverse order + LoggerPtr c2 = hierarchy->getLogger("order2.child.grandchild"); + LoggerPtr b2 = hierarchy->getLogger("order2.child"); + LoggerPtr a2 = hierarchy->getLogger("order2"); + + a2->setLevel(Level::getWarn()); + assertThresholdConsistent(a2); + assertThresholdConsistent(b2); + assertThresholdConsistent(c2); + + // Both should have same threshold + assertThresholdIs(c1, c2); + } + + // Test 27: Child created before parent + void testChildCreatedBeforeParent() + { + // Create child first + LoggerPtr child = hierarchy->getLogger("parent.child"); + LoggerPtr grandchild = hierarchy->getLogger("parent.child.grandchild"); + + assertThresholdConsistent(child); + assertThresholdConsistent(grandchild); + + // Now create parent and set its level + LoggerPtr parent = hierarchy->getLogger("parent"); + parent->setLevel(Level::getInfo()); + + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + assertThresholdConsistent(grandchild); + + // Child and grandchild should now inherit from parent + assertThresholdIs(Level::getInfo(), child); + assertThresholdIs(Level::getInfo(), grandchild); + + // Change parent level + parent->setLevel(Level::getDebug()); + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + assertThresholdConsistent(grandchild); + + assertThresholdIs(Level::getDebug(), child); + assertThresholdIs(Level::getDebug(), grandchild); + } + + // Test 28: Provision node scenario + void testProvisionNodeScenario() + { + // Create grandchild before intermediate parent exists + LoggerPtr grandchild1 = hierarchy->getLogger("a.b.c.d"); + LoggerPtr grandchild2 = hierarchy->getLogger("a.b.c.e"); + LoggerPtr grandchild3 = hierarchy->getLogger("a.b.c.f"); + + assertThresholdConsistent(grandchild1); + assertThresholdConsistent(grandchild2); + assertThresholdConsistent(grandchild3); + + // Create root ancestor + LoggerPtr a = hierarchy->getLogger("a"); + a->setLevel(Level::getWarn()); + + assertThresholdConsistent(a); + assertThresholdConsistent(grandchild1); + assertThresholdConsistent(grandchild2); + assertThresholdConsistent(grandchild3); + + assertThresholdIs(Level::getWarn(), grandchild1); + assertThresholdIs(Level::getWarn(), grandchild2); + assertThresholdIs(Level::getWarn(), grandchild3); + + // Now create intermediate parent + LoggerPtr abc = hierarchy->getLogger("a.b.c"); + abc->setLevel(Level::getDebug()); + + assertThresholdConsistent(a); + assertThresholdConsistent(abc); + assertThresholdConsistent(grandchild1); + assertThresholdConsistent(grandchild2); + assertThresholdConsistent(grandchild3); + + assertThresholdIs(Level::getWarn(), a); + assertThresholdIs(Level::getDebug(), abc); + assertThresholdIs(Level::getDebug(), grandchild1); + assertThresholdIs(Level::getDebug(), grandchild2); + assertThresholdIs(Level::getDebug(), grandchild3); + + // Override one grandchild + grandchild2->setLevel(Level::getTrace()); + assertThresholdConsistent(grandchild2); + assertThresholdIs(Level::getTrace(), grandchild2); + + // Change intermediate parent - should not affect overridden grandchild + abc->setLevel(Level::getError()); + assertThresholdConsistent(abc); + assertThresholdConsistent(grandchild1); + assertThresholdConsistent(grandchild2); + assertThresholdConsistent(grandchild3); + + assertThresholdIs(Level::getError(), grandchild1); + assertThresholdIs(Level::getTrace(), grandchild2); + assertThresholdIs(Level::getError(), grandchild3); + } + + // Additional Test 29: Multiple children created before parent + void testMultipleChildrenBeforeParent() + { + LoggerPtr child1 = hierarchy->getLogger("base.child1"); + LoggerPtr child2 = hierarchy->getLogger("base.child2"); + LoggerPtr child3 = hierarchy->getLogger("base.child3"); + LoggerPtr grandchild1 = hierarchy->getLogger("base.child1.grandchild"); + + assertThresholdConsistent(child1); + assertThresholdConsistent(child2); + assertThresholdConsistent(child3); + assertThresholdConsistent(grandchild1); + + // Now create parent + LoggerPtr base = hierarchy->getLogger("base"); + base->setLevel(Level::getInfo()); + + assertThresholdConsistent(base); + assertThresholdConsistent(child1); + assertThresholdConsistent(child2); + assertThresholdConsistent(child3); + assertThresholdConsistent(grandchild1); + + assertThresholdIs(Level::getInfo(), child1); + assertThresholdIs(Level::getInfo(), child2); + assertThresholdIs(Level::getInfo(), child3); + assertThresholdIs(Level::getInfo(), grandchild1); + } + + // Additional Test 30: Complex interleaved creation and level setting + void testComplexInterleavedCreationAndLevelSetting() + { + LoggerPtr root = hierarchy->getRootLogger(); + root->setLevel(Level::getFatal()); + + LoggerPtr c = hierarchy->getLogger("a.b.c"); + assertThresholdConsistent(c); + assertThresholdIs(Level::getFatal(), c); + + LoggerPtr a = hierarchy->getLogger("a"); + a->setLevel(Level::getError()); + assertThresholdConsistent(a); + assertThresholdConsistent(c); + assertThresholdIs(Level::getError(), c); + + LoggerPtr d = hierarchy->getLogger("a.b.c.d"); + assertThresholdConsistent(d); + assertThresholdIs(Level::getError(), d); + + c->setLevel(Level::getDebug()); + assertThresholdConsistent(a); + assertThresholdConsistent(c); + assertThresholdConsistent(d); + assertThresholdIs(Level::getError(), a); + assertThresholdIs(Level::getDebug(), c); + assertThresholdIs(Level::getDebug(), d); + + LoggerPtr b = hierarchy->getLogger("a.b"); + b->setLevel(Level::getWarn()); + assertThresholdConsistent(a); + assertThresholdConsistent(b); + assertThresholdConsistent(c); + assertThresholdConsistent(d); + + assertThresholdIs(Level::getError(), a); + assertThresholdIs(Level::getWarn(), b); + assertThresholdIs(Level::getDebug(), c); + assertThresholdIs(Level::getDebug(), d); + + // Set c to null - should inherit from b + c->setLevel(LevelPtr()); + assertThresholdConsistent(c); + assertThresholdConsistent(d); + assertThresholdIs(Level::getWarn(), c); + assertThresholdIs(Level::getWarn(), d); + } + + // Additional Test 31: Wide hierarchy (many siblings) + void testWideHierarchy() + { + LoggerPtr parent = hierarchy->getLogger("parent"); + parent->setLevel(Level::getInfo()); + + std::vector<LoggerPtr> children; + for (int i = 0; i < 20; ++i) + { + std::ostringstream oss; + oss << "parent.child" << i; + LoggerPtr child = hierarchy->getLogger(oss.str()); + children.push_back(child); + assertThresholdConsistent(child); + assertThresholdIs(Level::getInfo(), child); + } + + // Override some children + children[5]->setLevel(Level::getDebug()); + children[10]->setLevel(Level::getWarn()); + children[15]->setLevel(Level::getError()); + + for (size_t i = 0; i < children.size(); ++i) + { + assertThresholdConsistent(children[i]); + } + + assertThresholdIs(Level::getDebug(), children[5]); + assertThresholdIs(Level::getWarn(), children[10]); + assertThresholdIs(Level::getError(), children[15]); + assertThresholdIs(Level::getInfo(), children[0]); + assertThresholdIs(Level::getInfo(), children[19]); + + // Change parent level + parent->setLevel(Level::getTrace()); + + for (size_t i = 0; i < children.size(); ++i) + { + assertThresholdConsistent(children[i]); + } + + // Overridden children should keep their levels + assertThresholdIs(Level::getDebug(), children[5]); + assertThresholdIs(Level::getWarn(), children[10]); + assertThresholdIs(Level::getError(), children[15]); + // Non-overridden should inherit new level + assertThresholdIs(Level::getTrace(), children[0]); + assertThresholdIs(Level::getTrace(), children[19]); + } + + // Additional Test 32: Deep hierarchy with alternating overrides + void testDeepHierarchyAlternatingOverrides() + { + LoggerPtr root = hierarchy->getRootLogger(); + root->setLevel(Level::getError()); + + std::vector<LoggerPtr> loggers; + loggers.push_back(root); + + std::string name = "a"; + for (int i = 0; i < 10; ++i) + { + LoggerPtr logger = hierarchy->getLogger(name); + loggers.push_back(logger); + + // Set level on even indices + if (i % 2 == 0) + { + logger->setLevel(Level::getDebug()); + } + + assertThresholdConsistent(logger); + name += ".b"; + } + + // Verify all thresholds are consistent + for (size_t i = 0; i < loggers.size(); ++i) + { + assertThresholdConsistent(loggers[i]); + } + + // Verify expected levels + assertThresholdIs(Level::getError(), loggers[0]); // root + assertThresholdIs(Level::getDebug(), loggers[1]); // a (i=0, even) + assertThresholdIs(Level::getDebug(), loggers[2]); // a.b (i=1, odd, inherits) + assertThresholdIs(Level::getDebug(), loggers[3]); // a.b.b (i=2, even) + assertThresholdIs(Level::getDebug(), loggers[4]); // a.b.b.b (i=3, odd, inherits) + } + + // Additional Test 33: Set parent to same parent (no-op) + void testSetParentToSameParent() + { + LoggerPtr parent = hierarchy->getLogger("parent"); + LoggerPtr child = hierarchy->getLogger("parent.child"); + + parent->setLevel(Level::getInfo()); + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + + LoggerPtr currentParent = child->getParent(); + LOGUNIT_ASSERT(currentParent != nullptr); + + // Set parent to same parent (should be no-op) + child->setParent(currentParent); + assertThresholdConsistent(child); + assertThresholdIs(Level::getInfo(), child); + } + + // Additional Test 34: Root logger level changes affect entire hierarchy + void testRootLoggerAffectsEntireHierarchy() + { + LoggerPtr root = hierarchy->getRootLogger(); + + LoggerPtr a = hierarchy->getLogger("a"); + LoggerPtr ab = hierarchy->getLogger("a.b"); + LoggerPtr abc = hierarchy->getLogger("a.b.c"); + LoggerPtr x = hierarchy->getLogger("x"); + LoggerPtr xy = hierarchy->getLogger("x.y"); + + root->setLevel(Level::getWarn()); + + assertThresholdConsistent(root); + assertThresholdConsistent(a); + assertThresholdConsistent(ab); + assertThresholdConsistent(abc); + assertThresholdConsistent(x); + assertThresholdConsistent(xy); + + assertThresholdIs(Level::getWarn(), a); + assertThresholdIs(Level::getWarn(), ab); + assertThresholdIs(Level::getWarn(), abc); + assertThresholdIs(Level::getWarn(), x); + assertThresholdIs(Level::getWarn(), xy); + + root->setLevel(Level::getDebug()); + + assertThresholdConsistent(root); + assertThresholdConsistent(a); + assertThresholdConsistent(ab); + assertThresholdConsistent(abc); + assertThresholdConsistent(x); + assertThresholdConsistent(xy); + + assertThresholdIs(Level::getDebug(), a); + assertThresholdIs(Level::getDebug(), ab); + assertThresholdIs(Level::getDebug(), abc); + assertThresholdIs(Level::getDebug(), x); + assertThresholdIs(Level::getDebug(), xy); + } + + // Additional Test 35: Mixed null and non-null levels in hierarchy + void testMixedNullAndNonNullLevels() + { + LoggerPtr root = hierarchy->getRootLogger(); + LoggerPtr a = hierarchy->getLogger("a"); + LoggerPtr ab = hierarchy->getLogger("a.b"); + LoggerPtr abc = hierarchy->getLogger("a.b.c"); + LoggerPtr abcd = hierarchy->getLogger("a.b.c.d"); + + root->setLevel(Level::getError()); + a->setLevel(LevelPtr()); // null - should inherit from root + ab->setLevel(Level::getInfo()); + abc->setLevel(LevelPtr()); // null - should inherit from ab + abcd->setLevel(Level::getDebug()); + + assertThresholdConsistent(root); + assertThresholdConsistent(a); + assertThresholdConsistent(ab); + assertThresholdConsistent(abc); + assertThresholdConsistent(abcd); + + assertThresholdIs(Level::getError(), root); + assertThresholdIs(Level::getError(), a); + assertThresholdIs(Level::getInfo(), ab); + assertThresholdIs(Level::getInfo(), abc); + assertThresholdIs(Level::getDebug(), abcd); + + // Change ab level - abc should follow + ab->setLevel(Level::getWarn()); + assertThresholdConsistent(ab); + assertThresholdConsistent(abc); + assertThresholdConsistent(abcd); + + assertThresholdIs(Level::getWarn(), abc); + assertThresholdIs(Level::getDebug(), abcd); + } + + // Additional Test 36: Verify threshold after multiple parent changes + void testThresholdAfterMultipleParentChanges() + { + LoggerPtr p1 = hierarchy->getLogger("parent1"); + LoggerPtr p2 = hierarchy->getLogger("parent2"); + LoggerPtr p3 = hierarchy->getLogger("parent3"); + LoggerPtr child = hierarchy->getLogger("orphan"); + + p1->setLevel(Level::getTrace()); + p2->setLevel(Level::getInfo()); + p3->setLevel(Level::getFatal()); + + child->setParent(p1); + assertThresholdConsistent(child); + assertThresholdIs(Level::getTrace(), child); + + child->setParent(p2); + assertThresholdConsistent(child); + assertThresholdIs(Level::getInfo(), child); + + child->setParent(p3); + assertThresholdConsistent(child); + assertThresholdIs(Level::getFatal(), child); + + child->setParent(p1); + assertThresholdConsistent(child); + assertThresholdIs(Level::getTrace(), child); + + // Set child's own level + child->setLevel(Level::getWarn()); + assertThresholdConsistent(child); + assertThresholdIs(Level::getWarn(), child); + + // Change parent - child should keep its level + child->setParent(p2); + assertThresholdConsistent(child); + assertThresholdIs(Level::getWarn(), child); + } + + // Additional Test 37: Grandchild created before parent and middle ancestor + void testGrandchildBeforeParentAndMiddle() + { + LoggerPtr grandchild = hierarchy->getLogger("a.b.c.d.e.f"); + assertThresholdConsistent(grandchild); + + LoggerPtr root = hierarchy->getRootLogger(); + root->setLevel(Level::getError()); + assertThresholdConsistent(grandchild); + assertThresholdIs(Level::getError(), grandchild); + + LoggerPtr middle = hierarchy->getLogger("a.b.c"); + middle->setLevel(Level::getInfo()); + assertThresholdConsistent(middle); + assertThresholdConsistent(grandchild); + assertThresholdIs(Level::getInfo(), grandchild); + + LoggerPtr top = hierarchy->getLogger("a"); + top->setLevel(Level::getWarn()); + assertThresholdConsistent(top); + assertThresholdConsistent(middle); + assertThresholdConsistent(grandchild); + + // grandchild should still inherit from middle (closest ancestor with level) + assertThresholdIs(Level::getWarn(), top); + assertThresholdIs(Level::getInfo(), middle); + assertThresholdIs(Level::getInfo(), grandchild); + } + + // Additional Test 38: Stress test - many level changes + void testStressTestManyLevelChanges() + { + LoggerPtr root = hierarchy->getRootLogger(); + LoggerPtr parent = hierarchy->getLogger("stress.parent"); + LoggerPtr child = hierarchy->getLogger("stress.parent.child"); + LoggerPtr grandchild = hierarchy->getLogger("stress.parent.child.grandchild"); + + LevelPtr levels[] = { + Level::getTrace(), + Level::getDebug(), + Level::getInfo(), + Level::getWarn(), + Level::getError(), + Level::getFatal() + }; + + for (int iteration = 0; iteration < 50; ++iteration) + { + for (size_t i = 0; i < sizeof(levels)/sizeof(levels[0]); ++i) + { + root->setLevel(levels[i]); + assertThresholdConsistent(root); + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + assertThresholdConsistent(grandchild); + + parent->setLevel(levels[(i + 1) % (sizeof(levels)/sizeof(levels[0]))]); + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + assertThresholdConsistent(grandchild); + + child->setLevel(levels[(i + 2) % (sizeof(levels)/sizeof(levels[0]))]); + assertThresholdConsistent(child); + assertThresholdConsistent(grandchild); + + // Set to null and verify inheritance + child->setLevel(LevelPtr()); + assertThresholdConsistent(child); + assertThresholdConsistent(grandchild); + } + } + } + + // Additional Test 39: Verify consistency across different name patterns + void testDifferentNamePatterns() + { + // Single segment names + LoggerPtr single1 = hierarchy->getLogger("logger1"); + LoggerPtr single2 = hierarchy->getLogger("logger2"); + + // Multi-segment names + LoggerPtr multi1 = hierarchy->getLogger("com.example.app"); + LoggerPtr multi2 = hierarchy->getLogger("org.apache.log4cxx"); + + // Very long names + LoggerPtr longName = hierarchy->getLogger("a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p"); + + // Names with numbers + LoggerPtr numbered = hierarchy->getLogger("logger.v1.module2.class3"); + + LoggerPtr root = hierarchy->getRootLogger(); + root->setLevel(Level::getInfo()); + + assertThresholdConsistent(single1); + assertThresholdConsistent(single2); + assertThresholdConsistent(multi1); + assertThresholdConsistent(multi2); + assertThresholdConsistent(longName); + assertThresholdConsistent(numbered); + + single1->setLevel(Level::getDebug()); + assertThresholdConsistent(single1); + + LoggerPtr comExample = hierarchy->getLogger("com.example"); + comExample->setLevel(Level::getWarn()); + assertThresholdConsistent(comExample); + assertThresholdConsistent(multi1); + assertThresholdIs(Level::getWarn(), multi1); + } + + // Additional Test 40: Parent chain with all null levels except root + void testParentChainAllNullExceptRoot() + { + LoggerPtr root = hierarchy->getRootLogger(); + LoggerPtr a = hierarchy->getLogger("a"); + LoggerPtr ab = hierarchy->getLogger("a.b"); + LoggerPtr abc = hierarchy->getLogger("a.b.c"); + LoggerPtr abcd = hierarchy->getLogger("a.b.c.d"); + + root->setLevel(Level::getWarn()); + // All others have null level (default) + + assertThresholdConsistent(root); + assertThresholdConsistent(a); + assertThresholdConsistent(ab); + assertThresholdConsistent(abc); + assertThresholdConsistent(abcd); + + // All should inherit from root + assertThresholdIs(Level::getWarn(), a); + assertThresholdIs(Level::getWarn(), ab); + assertThresholdIs(Level::getWarn(), abc); + assertThresholdIs(Level::getWarn(), abcd); + + // Change root + root->setLevel(Level::getDebug()); + + assertThresholdConsistent(root); + assertThresholdConsistent(a); + assertThresholdConsistent(ab); + assertThresholdConsistent(abc); + assertThresholdConsistent(abcd); + + assertThresholdIs(Level::getDebug(), a); + assertThresholdIs(Level::getDebug(), ab); + assertThresholdIs(Level::getDebug(), abc); + assertThresholdIs(Level::getDebug(), abcd); + } + + // Additional Test 41: Concurrent hierarchy branches + void testConcurrentHierarchyBranches() + { + LoggerPtr root = hierarchy->getRootLogger(); + root->setLevel(Level::getError()); + + // Branch 1: com.example.app + LoggerPtr com = hierarchy->getLogger("com"); + LoggerPtr comExample = hierarchy->getLogger("com.example"); + LoggerPtr comExampleApp = hierarchy->getLogger("com.example.app"); + + // Branch 2: org.apache.log4cxx + LoggerPtr org = hierarchy->getLogger("org"); + LoggerPtr orgApache = hierarchy->getLogger("org.apache"); + LoggerPtr orgApacheLog4cxx = hierarchy->getLogger("org.apache.log4cxx"); + + // Set different levels on branches + com->setLevel(Level::getInfo()); + org->setLevel(Level::getDebug()); + + assertThresholdConsistent(com); + assertThresholdConsistent(comExample); + assertThresholdConsistent(comExampleApp); + assertThresholdConsistent(org); + assertThresholdConsistent(orgApache); + assertThresholdConsistent(orgApacheLog4cxx); + + assertThresholdIs(Level::getInfo(), comExample); + assertThresholdIs(Level::getInfo(), comExampleApp); + assertThresholdIs(Level::getDebug(), orgApache); + assertThresholdIs(Level::getDebug(), orgApacheLog4cxx); + + // Override in middle of one branch + comExample->setLevel(Level::getWarn()); + assertThresholdConsistent(comExample); + assertThresholdConsistent(comExampleApp); + + assertThresholdIs(Level::getWarn(), comExample); + assertThresholdIs(Level::getWarn(), comExampleApp); + + // Other branch should be unaffected + assertThresholdConsistent(org); + assertThresholdConsistent(orgApache); + assertThresholdConsistent(orgApacheLog4cxx); + assertThresholdIs(Level::getDebug(), orgApache); + } + + // Additional Test 42: Setting level on logger with existing children + void testSetLevelOnLoggerWithExistingChildren() + { + LoggerPtr parent = hierarchy->getLogger("parent"); + LoggerPtr child1 = hierarchy->getLogger("parent.child1"); + LoggerPtr child2 = hierarchy->getLogger("parent.child2"); + LoggerPtr grandchild1 = hierarchy->getLogger("parent.child1.grandchild"); + LoggerPtr grandchild2 = hierarchy->getLogger("parent.child2.grandchild"); + + // All start with root's level + LoggerPtr root = hierarchy->getRootLogger(); + root->setLevel(Level::getError()); + + assertThresholdConsistent(parent); + assertThresholdConsistent(child1); + assertThresholdConsistent(child2); + assertThresholdConsistent(grandchild1); + assertThresholdConsistent(grandchild2); + + // Set parent level - should propagate to all children + parent->setLevel(Level::getInfo()); + + assertThresholdConsistent(parent); + assertThresholdConsistent(child1); + assertThresholdConsistent(child2); + assertThresholdConsistent(grandchild1); + assertThresholdConsistent(grandchild2); + + assertThresholdIs(Level::getInfo(), child1); + assertThresholdIs(Level::getInfo(), child2); + assertThresholdIs(Level::getInfo(), grandchild1); + assertThresholdIs(Level::getInfo(), grandchild2); + + // Override one child + child1->setLevel(Level::getDebug()); + assertThresholdConsistent(child1); + assertThresholdConsistent(grandchild1); + + assertThresholdIs(Level::getDebug(), child1); + assertThresholdIs(Level::getDebug(), grandchild1); + + // Change parent again - overridden child should keep its level + parent->setLevel(Level::getWarn()); + + assertThresholdConsistent(parent); + assertThresholdConsistent(child1); + assertThresholdConsistent(child2); + assertThresholdConsistent(grandchild1); + assertThresholdConsistent(grandchild2); + + assertThresholdIs(Level::getDebug(), child1); + assertThresholdIs(Level::getWarn(), child2); + assertThresholdIs(Level::getDebug(), grandchild1); + assertThresholdIs(Level::getWarn(), grandchild2); + } + + // Additional Test 43: Alternating setLevel and setParent calls + void testAlternatingSetLevelAndSetParent() + { + LoggerPtr p1 = hierarchy->getLogger("p1"); + LoggerPtr p2 = hierarchy->getLogger("p2"); + LoggerPtr child = hierarchy->getLogger("child"); + + p1->setLevel(Level::getInfo()); + assertThresholdConsistent(p1); + + child->setParent(p1); + assertThresholdConsistent(child); + assertThresholdIs(Level::getInfo(), child); + + child->setLevel(Level::getDebug()); + assertThresholdConsistent(child); + assertThresholdIs(Level::getDebug(), child); + + p2->setLevel(Level::getWarn()); + assertThresholdConsistent(p2); + + child->setParent(p2); + assertThresholdConsistent(child); + assertThresholdIs(Level::getDebug(), child); // Keeps own level + + child->setLevel(LevelPtr()); + assertThresholdConsistent(child); + assertThresholdIs(Level::getWarn(), child); // Now inherits from p2 + + child->setParent(p1); + assertThresholdConsistent(child); + assertThresholdIs(Level::getInfo(), child); // Now inherits from p1 + + p1->setLevel(Level::getError()); + assertThresholdConsistent(p1); + assertThresholdConsistent(child); + assertThresholdIs(Level::getError(), child); + } + + // Additional Test 44: Verify threshold with OFF and ALL levels + void testOffAndAllLevels() + { + LoggerPtr parent = hierarchy->getLogger("parent"); + LoggerPtr child = hierarchy->getLogger("parent.child"); + + parent->setLevel(Level::getOff()); + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + assertThresholdIs(Level::getOff(), parent); + assertThresholdIs(Level::getOff(), child); + + parent->setLevel(Level::getAll()); + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + assertThresholdIs(Level::getAll(), parent); + assertThresholdIs(Level::getAll(), child); + + child->setLevel(Level::getOff()); + assertThresholdConsistent(child); + assertThresholdIs(Level::getOff(), child); + + parent->setLevel(Level::getTrace()); + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + assertThresholdIs(Level::getTrace(), parent); + assertThresholdIs(Level::getOff(), child); // Keeps OFF + } + + // Additional Test 45: Complex scenario with provision nodes and level changes + void testComplexProvisionNodeScenario() + { + // Create deep child first + LoggerPtr deepChild = hierarchy->getLogger("a.b.c.d.e.f.g"); + assertThresholdConsistent(deepChild); + + LoggerPtr root = hierarchy->getRootLogger(); + root->setLevel(Level::getFatal()); + assertThresholdConsistent(deepChild); + assertThresholdIs(Level::getFatal(), deepChild); + + // Create intermediate ancestors in random order + LoggerPtr c = hierarchy->getLogger("a.b.c"); + c->setLevel(Level::getError()); + assertThresholdConsistent(c); + assertThresholdConsistent(deepChild); + assertThresholdIs(Level::getError(), deepChild); + + LoggerPtr a = hierarchy->getLogger("a"); + a->setLevel(Level::getWarn()); + assertThresholdConsistent(a); + assertThresholdConsistent(c); + assertThresholdConsistent(deepChild); + assertThresholdIs(Level::getWarn(), a); + assertThresholdIs(Level::getError(), c); + assertThresholdIs(Level::getError(), deepChild); + + LoggerPtr e = hierarchy->getLogger("a.b.c.d.e"); + e->setLevel(Level::getDebug()); + assertThresholdConsistent(e); + assertThresholdConsistent(deepChild); + assertThresholdIs(Level::getDebug(), e); + assertThresholdIs(Level::getDebug(), deepChild); + + LoggerPtr b = hierarchy->getLogger("a.b"); + b->setLevel(Level::getInfo()); + assertThresholdConsistent(b); + assertThresholdConsistent(c); + assertThresholdConsistent(e); + assertThresholdConsistent(deepChild); + + assertThresholdIs(Level::getInfo(), b); + assertThresholdIs(Level::getError(), c); + assertThresholdIs(Level::getDebug(), e); + assertThresholdIs(Level::getDebug(), deepChild); + + // Set e to null - deepChild should inherit from c + e->setLevel(LevelPtr()); + assertThresholdConsistent(e); + assertThresholdConsistent(deepChild); + assertThresholdIs(Level::getError(), e); + assertThresholdIs(Level::getError(), deepChild); + } + + // Additional Test 46: Multiple siblings with different levels + void testMultipleSiblingsWithDifferentLevels() + { + LoggerPtr parent = hierarchy->getLogger("parent"); + parent->setLevel(Level::getInfo()); + + std::vector<LoggerPtr> siblings; + LevelPtr levels[] = { + Level::getTrace(), + Level::getDebug(), + LevelPtr(), // null - inherits + Level::getWarn(), + Level::getError(), + LevelPtr(), // null - inherits + Level::getFatal() + }; + + for (size_t i = 0; i < sizeof(levels)/sizeof(levels[0]); ++i) + { + std::ostringstream oss; + oss << "parent.sibling" << i; + LoggerPtr sibling = hierarchy->getLogger(oss.str()); + sibling->setLevel(levels[i]); + siblings.push_back(sibling); + assertThresholdConsistent(sibling); + } + + // Verify each sibling has correct threshold + assertThresholdIs(Level::getTrace(), siblings[0]); + assertThresholdIs(Level::getDebug(), siblings[1]); + assertThresholdIs(Level::getInfo(), siblings[2]); // inherits + assertThresholdIs(Level::getWarn(), siblings[3]); + assertThresholdIs(Level::getError(), siblings[4]); + assertThresholdIs(Level::getInfo(), siblings[5]); // inherits + assertThresholdIs(Level::getFatal(), siblings[6]); + + // Change parent level + parent->setLevel(Level::getDebug()); + + for (size_t i = 0; i < siblings.size(); ++i) + { + assertThresholdConsistent(siblings[i]); + } + + // Only inheriting siblings should change + assertThresholdIs(Level::getTrace(), siblings[0]); + assertThresholdIs(Level::getDebug(), siblings[1]); + assertThresholdIs(Level::getDebug(), siblings[2]); // changed + assertThresholdIs(Level::getWarn(), siblings[3]); + assertThresholdIs(Level::getError(), siblings[4]); + assertThresholdIs(Level::getDebug(), siblings[5]); // changed + assertThresholdIs(Level::getFatal(), siblings[6]); + } + + // Additional Test 47: Parent chain with gaps + void testParentChainWithGaps() + { + LoggerPtr root = hierarchy->getRootLogger(); + root->setLevel(Level::getError()); + + // Create loggers with gaps in hierarchy + LoggerPtr level2 = hierarchy->getLogger("a.b"); + LoggerPtr level5 = hierarchy->getLogger("a.b.c.d.e"); + + assertThresholdConsistent(level2); + assertThresholdConsistent(level5); + + // Both should inherit from root + assertThresholdIs(Level::getError(), level2); + assertThresholdIs(Level::getError(), level5); + + // Set level on level2 + level2->setLevel(Level::getInfo()); + assertThresholdConsistent(level2); + assertThresholdConsistent(level5); + + // level5 should now inherit from level2 + assertThresholdIs(Level::getInfo(), level5); + + // Fill in a gap + LoggerPtr level3 = hierarchy->getLogger("a.b.c"); + level3->setLevel(Level::getDebug()); + assertThresholdConsistent(level3); + assertThresholdConsistent(level5); + + // level5 should now inherit from level3 + assertThresholdIs(Level::getDebug(), level5); + + // Fill in another gap + LoggerPtr level4 = hierarchy->getLogger("a.b.c.d"); + assertThresholdConsistent(level4); + assertThresholdConsistent(level5); + + // level4 and level5 should inherit from level3 + assertThresholdIs(Level::getDebug(), level4); + assertThresholdIs(Level::getDebug(), level5); + } + + // Additional Test 48: Verify threshold after hierarchy reset + void testThresholdAfterHierarchyOperations() + { + LoggerPtr parent = hierarchy->getLogger("parent"); + LoggerPtr child = hierarchy->getLogger("parent.child"); + + parent->setLevel(Level::getInfo()); + child->setLevel(Level::getDebug()); + + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + + assertThresholdIs(Level::getInfo(), parent); + assertThresholdIs(Level::getDebug(), child); + + // After getting effective level, threshold should still be consistent + LevelPtr effectiveLevel = child->getEffectiveLevel(); + assertThresholdConsistent(child); + assertThresholdIs(effectiveLevel, child); + } + + // Additional Test 49: Cross-branch hierarchy changes + void testCrossBranchHierarchyChanges() + { + LoggerPtr root = hierarchy->getRootLogger(); + root->setLevel(Level::getWarn()); + + // Branch A + LoggerPtr a = hierarchy->getLogger("a"); + LoggerPtr ab = hierarchy->getLogger("a.b"); + LoggerPtr abc = hierarchy->getLogger("a.b.c"); + + // Branch X + LoggerPtr x = hierarchy->getLogger("x"); + LoggerPtr xy = hierarchy->getLogger("x.y"); + LoggerPtr xyz = hierarchy->getLogger("x.y.z"); + + a->setLevel(Level::getInfo()); + x->setLevel(Level::getDebug()); + + assertThresholdConsistent(a); + assertThresholdConsistent(ab); + assertThresholdConsistent(abc); + assertThresholdConsistent(x); + assertThresholdConsistent(xy); + assertThresholdConsistent(xyz); + + assertThresholdIs(Level::getInfo(), ab); + assertThresholdIs(Level::getInfo(), abc); + assertThresholdIs(Level::getDebug(), xy); + assertThresholdIs(Level::getDebug(), xyz); + + // Change root - should affect both branches (where not overridden) + root->setLevel(Level::getError()); + + assertThresholdConsistent(root); + assertThresholdConsistent(a); + assertThresholdConsistent(ab); + assertThresholdConsistent(abc); + assertThresholdConsistent(x); + assertThresholdConsistent(xy); + assertThresholdConsistent(xyz); + + // Branch A still has its override + assertThresholdIs(Level::getInfo(), a); + assertThresholdIs(Level::getInfo(), ab); + assertThresholdIs(Level::getInfo(), abc); + + // Branch X still has its override + assertThresholdIs(Level::getDebug(), x); + assertThresholdIs(Level::getDebug(), xy); + assertThresholdIs(Level::getDebug(), xyz); + + // Set middle of branch A to null + a->setLevel(LevelPtr()); + assertThresholdConsistent(a); + assertThresholdConsistent(ab); + assertThresholdConsistent(abc); + + // Branch A should now inherit from root + assertThresholdIs(Level::getError(), a); + assertThresholdIs(Level::getError(), ab); + assertThresholdIs(Level::getError(), abc); + + // Branch X should be unaffected + assertThresholdIs(Level::getDebug(), x); + assertThresholdIs(Level::getDebug(), xy); + assertThresholdIs(Level::getDebug(), xyz); + } + + // Additional Test 50: Verify threshold with extremely deep hierarchy + void testExtremelyDeepHierarchy() + { + LoggerPtr root = hierarchy->getRootLogger(); + root->setLevel(Level::getWarn()); + + std::string name = "level"; + LoggerPtr previous = root; + std::vector<LoggerPtr> loggers; + + // Create 50-level deep hierarchy + for (int i = 1; i <= 50; ++i) + { + std::ostringstream oss; + oss << name << '.' << i; + name = oss.str(); + + LoggerPtr logger = hierarchy->getLogger(name); + loggers.push_back(logger); + assertThresholdConsistent(logger); + assertThresholdIs(Level::getWarn(), logger); + } + + // Set level at depth 25 + loggers[24]->setLevel(Level::getDebug()); + + // Verify all loggers + for (size_t i = 0; i < loggers.size(); ++i) + { + assertThresholdConsistent(loggers[i]); + + if (i < 24) + { + assertThresholdIs(Level::getWarn(), loggers[i]); + } + else + { + assertThresholdIs(Level::getDebug(), loggers[i]); + } + } + + // Set level at depth 40 + loggers[39]->setLevel(Level::getTrace()); + + for (size_t i = 0; i < loggers.size(); ++i) + { + assertThresholdConsistent(loggers[i]); + + if (i < 24) + { + assertThresholdIs(Level::getWarn(), loggers[i]); + } + else if (i < 39) + { + assertThresholdIs(Level::getDebug(), loggers[i]); + } + else + { + assertThresholdIs(Level::getTrace(), loggers[i]); + } + } + + // Change root level + root->setLevel(Level::getError()); + + for (size_t i = 0; i < loggers.size(); ++i) + { + assertThresholdConsistent(loggers[i]); + + if (i < 24) + { + assertThresholdIs(Level::getError(), loggers[i]); + } + else if (i < 39) + { + assertThresholdIs(Level::getDebug(), loggers[i]); + } + else + { + assertThresholdIs(Level::getTrace(), loggers[i]); + } + } + } + + // Additional Test 51: Verify threshold consistency during logger retrieval + void testThresholdConsistencyDuringRetrieval() + { + LoggerPtr root = hierarchy->getRootLogger(); + root->setLevel(Level::getInfo()); + + // Get logger multiple times and verify consistency each time + for (int i = 0; i < 10; ++i) + { + LoggerPtr logger = hierarchy->getLogger("test.logger"); + assertThresholdConsistent(logger); + assertThresholdIs(Level::getInfo(), logger); + } + + // Set level on the logger + LoggerPtr logger = hierarchy->getLogger("test.logger"); + logger->setLevel(Level::getDebug()); + + // Get it again and verify + for (int i = 0; i < 10; ++i) + { + LoggerPtr sameLogger = hierarchy->getLogger("test.logger"); + assertThresholdConsistent(sameLogger); + assertThresholdIs(Level::getDebug(), sameLogger); + } + } + + // Additional Test 52: Threshold consistency with logger factory + void testThresholdConsistencyWithLoggerFactory() + { + LoggerPtr root = hierarchy->getRootLogger(); + root->setLevel(Level::getWarn()); + spi::LoggerFactoryPtr factory = +#if LOG4CXX_ABI_VERSION <= 15 + std::make_shared<DefaultLoggerFactory>(); +#else + std::make_shared<LoggerFactory>(); +#endif + LoggerPtr logger1 = hierarchy->getLogger("factory.test1", factory); + LoggerPtr logger2 = hierarchy->getLogger("factory.test2", factory); + + assertThresholdConsistent(logger1); + assertThresholdConsistent(logger2); + + assertThresholdIs(Level::getWarn(), logger1); + assertThresholdIs(Level::getWarn(), logger2); + + logger1->setLevel(Level::getDebug()); + assertThresholdConsistent(logger1); + assertThresholdConsistent(logger2); + + assertThresholdIs(Level::getDebug(), logger1); + assertThresholdIs(Level::getWarn(), logger2); + } + + // Additional Test 53: Verify threshold after parent-child swap + void testThresholdAfterParentChildSwap() + { + LoggerPtr logger1 = hierarchy->getLogger("swap.test1"); + LoggerPtr logger2 = hierarchy->getLogger("swap.test2"); + + logger1->setLevel(Level::getInfo()); + logger2->setLevel(Level::getDebug()); + + assertThresholdConsistent(logger1); + assertThresholdConsistent(logger2); + + LoggerPtr child = hierarchy->getLogger("child"); + + // Set logger1 as parent + child->setParent(logger1); + assertThresholdConsistent(child); + assertThresholdIs(Level::getInfo(), child); + + // Swap to logger2 as parent + child->setParent(logger2); + assertThresholdConsistent(child); + assertThresholdIs(Level::getDebug(), child); + + // Swap back to logger1 + child->setParent(logger1); + assertThresholdConsistent(child); + assertThresholdIs(Level::getInfo(), child); + + // Change logger1's level while it's the parent + logger1->setLevel(Level::getWarn()); + assertThresholdConsistent(logger1); + assertThresholdConsistent(child); + assertThresholdIs(Level::getWarn(), child); + } + + // Additional Test 54: Threshold with all levels set to same value + void testThresholdWithAllSameLevel() + { + LoggerPtr root = hierarchy->getRootLogger(); + LoggerPtr a = hierarchy->getLogger("a"); + LoggerPtr ab = hierarchy->getLogger("a.b"); + LoggerPtr abc = hierarchy->getLogger("a.b.c"); + + // Set all to same level + LevelPtr sameLevel = Level::getInfo(); + root->setLevel(sameLevel); + a->setLevel(sameLevel); + ab->setLevel(sameLevel); + abc->setLevel(sameLevel); + + assertThresholdConsistent(root); + assertThresholdConsistent(a); + assertThresholdConsistent(ab); + assertThresholdConsistent(abc); + + assertThresholdIs(Level::getInfo(), root); + assertThresholdIs(Level::getInfo(), a); + assertThresholdIs(Level::getInfo(), ab); + assertThresholdIs(Level::getInfo(), abc); + + // Set middle one to null - should still be INFO + ab->setLevel(LevelPtr()); + assertThresholdConsistent(ab); + assertThresholdIs(Level::getInfo(), ab); + } + + // Additional Test 55: Threshold after rapid parent reassignments + void testThresholdAfterRapidParentReassignments() + { + LoggerPtr p1 = hierarchy->getLogger("p1"); + LoggerPtr p2 = hierarchy->getLogger("p2"); + LoggerPtr p3 = hierarchy->getLogger("p3"); + LoggerPtr child = hierarchy->getLogger("child"); + + p1->setLevel(Level::getTrace()); + p2->setLevel(Level::getDebug()); + p3->setLevel(Level::getInfo()); + + for (int i = 0; i < 100; ++i) + { + child->setParent(p1); + assertThresholdConsistent(child); + assertThresholdIs(Level::getTrace(), child); + + child->setParent(p2); + assertThresholdConsistent(child); + assertThresholdIs(Level::getDebug(), child); + + child->setParent(p3); + assertThresholdConsistent(child); + assertThresholdIs(Level::getInfo(), child); + } + } + + // Additional Test 56: Threshold with zigzag level pattern + void testThresholdWithZigzagLevelPattern() + { + LoggerPtr root = hierarchy->getRootLogger(); + LoggerPtr l1 = hierarchy->getLogger("a"); + LoggerPtr l2 = hierarchy->getLogger("a.b"); + LoggerPtr l3 = hierarchy->getLogger("a.b.c"); + LoggerPtr l4 = hierarchy->getLogger("a.b.c.d"); + LoggerPtr l5 = hierarchy->getLogger("a.b.c.d.e"); + + // Set zigzag pattern: high, low, high, low, high + root->setLevel(Level::getError()); // high + l1->setLevel(Level::getDebug()); // low + l2->setLevel(Level::getWarn()); // high + l3->setLevel(Level::getTrace()); // low + l4->setLevel(Level::getFatal()); // high + + assertThresholdConsistent(root); + assertThresholdConsistent(l1); + assertThresholdConsistent(l2); + assertThresholdConsistent(l3); + assertThresholdConsistent(l4); + assertThresholdConsistent(l5); + + assertThresholdIs(Level::getError(), root); + assertThresholdIs(Level::getDebug(), l1); + assertThresholdIs(Level::getWarn(), l2); + assertThresholdIs(Level::getTrace(), l3); + assertThresholdIs(Level::getFatal(), l4); + assertThresholdIs(Level::getFatal(), l5); // inherits from l4 + } + + // Additional Test 57: Threshold after removing and re-adding levels + void testThresholdAfterRemovingAndReaddingLevels() + { + LoggerPtr parent = hierarchy->getLogger("parent"); + LoggerPtr child = hierarchy->getLogger("parent.child"); + LoggerPtr grandchild = hierarchy->getLogger("parent.child.grandchild"); + + parent->setLevel(Level::getWarn()); + child->setLevel(Level::getDebug()); + + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + assertThresholdConsistent(grandchild); + + assertThresholdIs(Level::getWarn(), parent); + assertThresholdIs(Level::getDebug(), child); + assertThresholdIs(Level::getDebug(), grandchild); + + // Remove child's level + child->setLevel(LevelPtr()); + assertThresholdConsistent(child); + assertThresholdConsistent(grandchild); + assertThresholdIs(Level::getWarn(), child); + assertThresholdIs(Level::getWarn(), grandchild); + + // Re-add child's level + child->setLevel(Level::getInfo()); + assertThresholdConsistent(child); + assertThresholdConsistent(grandchild); + assertThresholdIs(Level::getInfo(), child); + assertThresholdIs(Level::getInfo(), grandchild); + + // Remove parent's level + parent->setLevel(LevelPtr()); + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + assertThresholdConsistent(grandchild); + + // Parent should inherit from root, child keeps its level + LoggerPtr root = hierarchy->getRootLogger(); + assertThresholdIs(root->getEffectiveLevel(), parent); + assertThresholdIs(Level::getInfo(), child); + assertThresholdIs(Level::getInfo(), grandchild); + + // Re-add parent's level + parent->setLevel(Level::getError()); + assertThresholdConsistent(parent); + assertThresholdConsistent(child); + assertThresholdConsistent(grandchild); + assertThresholdIs(Level::getError(), parent); + assertThresholdIs(Level::getInfo(), child); + assertThresholdIs(Level::getInfo(), grandchild); + } + + // Additional Test 58: Threshold consistency with diamond-shaped hierarchy + void testThresholdWithDiamondHierarchy() + { + LoggerPtr root = hierarchy->getRootLogger(); + root->setLevel(Level::getError()); + + // Create diamond pattern + LoggerPtr top = hierarchy->getLogger("top"); + LoggerPtr left = hierarchy->getLogger("top.left"); + LoggerPtr right = hierarchy->getLogger("top.right"); + LoggerPtr bottom = hierarchy->getLogger("top.left.bottom"); + + // Note: bottom can only have one parent in the hierarchy + // It will be under "top.left" by its name + + top->setLevel(Level::getWarn()); + left->setLevel(Level::getInfo()); + right->setLevel(Level::getDebug()); + + assertThresholdConsistent(root); + assertThresholdConsistent(top); + assertThresholdConsistent(left); + assertThresholdConsistent(right); + assertThresholdConsistent(bottom); + + assertThresholdIs(Level::getWarn(), top); + assertThresholdIs(Level::getInfo(), left); + assertThresholdIs(Level::getDebug(), right); + assertThresholdIs(Level::getInfo(), bottom); // inherits from left + + // Change top level + top->setLevel(Level::getTrace()); + assertThresholdConsistent(top); + assertThresholdConsistent(left); + assertThresholdConsistent(right); + assertThresholdConsistent(bottom); + + // left, right, and bottom should keep their levels + assertThresholdIs(Level::getTrace(), top); + assertThresholdIs(Level::getInfo(), left); + assertThresholdIs(Level::getDebug(), right); + assertThresholdIs(Level::getInfo(), bottom); + } + + // Additional Test 59: Threshold with very long logger names + void testThresholdWithVeryLongLoggerNames() + { + std::string longName = "very.long.logger.name.with.many.segments.to.test.the.hierarchy"; + longName += ".and.even.more.segments.to.make.it.really.long.and.complex"; + longName += ".final.segment.at.the.end"; + + LoggerPtr logger = hierarchy->getLogger(longName); + assertThresholdConsistent(logger); + + LoggerPtr root = hierarchy->getRootLogger(); + root->setLevel(Level::getInfo()); + assertThresholdConsistent(logger); + assertThresholdIs(Level::getInfo(), logger); + + // Set level on intermediate ancestor + LoggerPtr intermediate = hierarchy->getLogger("very.long.logger.name.with.many"); + intermediate->setLevel(Level::getDebug()); + assertThresholdConsistent(intermediate); + assertThresholdConsistent(logger); + assertThresholdIs(Level::getDebug(), logger); + + // Set level on the long logger itself + logger->setLevel(Level::getWarn()); + assertThresholdConsistent(logger); + assertThresholdIs(Level::getWarn(), logger); + } + + // Additional Test 60: Threshold after setting same level multiple times + void testThresholdAfterSettingSameLevelMultipleTimes() + { + LoggerPtr logger = hierarchy->getLogger("test"); + + for (int i = 0; i < 50; ++i) + { + logger->setLevel(Level::getInfo()); + assertThresholdConsistent(logger); + assertThresholdIs(Level::getInfo(), logger); + } + + logger->setLevel(Level::getDebug()); + assertThresholdConsistent(logger); + assertThresholdIs(Level::getDebug(), logger); + + for (int i = 0; i < 50; ++i) + { + logger->setLevel(Level::getDebug()); + assertThresholdConsistent(logger); + assertThresholdIs(Level::getDebug(), logger); + } + } + + // Additional Test 61: Complex scenario mixing all operations + void testComplexMixedOperations() + { + LoggerPtr root = hierarchy->getRootLogger(); + root->setLevel(Level::getWarn()); + + // Create loggers in mixed order + LoggerPtr deep = hierarchy->getLogger("a.b.c.d.e.f"); + assertThresholdConsistent(deep); + + LoggerPtr mid = hierarchy->getLogger("a.b.c"); + mid->setLevel(Level::getInfo()); + assertThresholdConsistent(mid); + assertThresholdConsistent(deep); + + LoggerPtr top = hierarchy->getLogger("a"); + top->setLevel(Level::getError()); + assertThresholdConsistent(top); + assertThresholdConsistent(mid); + assertThresholdConsistent(deep); + + assertThresholdIs(Level::getError(), top); + assertThresholdIs(Level::getInfo(), mid); + assertThresholdIs(Level::getInfo(), deep); + + // Set deep's level + deep->setLevel(Level::getDebug()); + assertThresholdConsistent(deep); + assertThresholdIs(Level::getDebug(), deep); + + // Create sibling + LoggerPtr sibling = hierarchy->getLogger("a.b.c.d.e.g"); + assertThresholdConsistent(sibling); + assertThresholdIs(Level::getInfo(), sibling); + + // Change mid to null + mid->setLevel(LevelPtr()); + assertThresholdConsistent(mid); + assertThresholdConsistent(deep); + assertThresholdConsistent(sibling); + + assertThresholdIs(Level::getError(), mid); + assertThresholdIs(Level::getDebug(), deep); + assertThresholdIs(Level::getError(), sibling); + + // Change top + top->setLevel(Level::getTrace()); + assertThresholdConsistent(top); + assertThresholdConsistent(mid); + assertThresholdConsistent(deep); + assertThresholdConsistent(sibling); + + assertThresholdIs(Level::getTrace(), top); + assertThresholdIs(Level::getTrace(), mid); + assertThresholdIs(Level::getDebug(), deep); + assertThresholdIs(Level::getTrace(), sibling); + + // Create intermediate logger + LoggerPtr intermediate = hierarchy->getLogger("a.b"); + intermediate->setLevel(Level::getFatal()); + assertThresholdConsistent(intermediate); + assertThresholdConsistent(mid); + assertThresholdConsistent(deep); + assertThresholdConsistent(sibling); + + assertThresholdIs(Level::getFatal(), intermediate); + assertThresholdIs(Level::getFatal(), mid); + assertThresholdIs(Level::getDebug(), deep); + assertThresholdIs(Level::getFatal(), sibling); + } + + // Additional Test 62: Threshold after parent change with grandchildren + void testThresholdAfterParentChangeWithGrandchildren() + { + LoggerPtr p1 = hierarchy->getLogger("p1"); + LoggerPtr p2 = hierarchy->getLogger("p2"); + LoggerPtr child = hierarchy->getLogger("child"); + LoggerPtr grandchild = hierarchy->getLogger("child.grandchild"); + LoggerPtr greatGrandchild = hierarchy->getLogger("child.grandchild.great"); + + p1->setLevel(Level::getInfo()); + p2->setLevel(Level::getError()); + + child->setParent(p1); + assertThresholdConsistent(child); + assertThresholdConsistent(grandchild); + assertThresholdConsistent(greatGrandchild); + + assertThresholdIs(Level::getInfo(), child); + assertThresholdIs(Level::getInfo(), grandchild); + assertThresholdIs(Level::getInfo(), greatGrandchild); + + // Change parent - all descendants should update + child->setParent(p2); + assertThresholdConsistent(child); + assertThresholdConsistent(grandchild); + assertThresholdConsistent(greatGrandchild); + + assertThresholdIs(Level::getError(), child); + assertThresholdIs(Level::getError(), grandchild); + assertThresholdIs(Level::getError(), greatGrandchild); + + // Set grandchild's level + grandchild->setLevel(Level::getDebug()); + assertThresholdConsistent(grandchild); + assertThresholdConsistent(greatGrandchild); + + assertThresholdIs(Level::getDebug(), grandchild); + assertThresholdIs(Level::getDebug(), greatGrandchild); + + // Change child's parent again - grandchild should keep its level + child->setParent(p1); + assertThresholdConsistent(child); + assertThresholdConsistent(grandchild); + assertThresholdConsistent(greatGrandchild); + + assertThresholdIs(Level::getInfo(), child); + assertThresholdIs(Level::getDebug(), grandchild); + assertThresholdIs(Level::getDebug(), greatGrandchild); + } + + // Additional Test 63: Verify threshold with empty logger name + void testThresholdWithEmptyLoggerName() + { + // Root logger has empty name + LoggerPtr root = hierarchy->getRootLogger(); + root->setLevel(Level::getInfo()); + assertThresholdConsistent(root); + assertThresholdIs(Level::getInfo(), root); + + LoggerPtr child = hierarchy->getLogger("child"); + assertThresholdConsistent(child); + assertThresholdIs(Level::getInfo(), child); + } + + // Additional Test 64: Threshold with single character logger names + void testThresholdWithSingleCharacterNames() + { + LoggerPtr a = hierarchy->getLogger("a"); + LoggerPtr ab = hierarchy->getLogger("a.b"); + LoggerPtr abc = hierarchy->getLogger("a.b.c"); + LoggerPtr abcd = hierarchy->getLogger("a.b.c.d"); + + a->setLevel(Level::getWarn()); + assertThresholdConsistent(a); + assertThresholdConsistent(ab); + assertThresholdConsistent(abc); + assertThresholdConsistent(abcd); + + assertThresholdIs(Level::getWarn(), ab); + assertThresholdIs(Level::getWarn(), abc); + assertThresholdIs(Level::getWarn(), abcd); + + abc->setLevel(Level::getDebug()); + assertThresholdConsistent(abc); + assertThresholdConsistent(abcd); + + assertThresholdIs(Level::getDebug(), abc); + assertThresholdIs(Level::getDebug(), abcd); + } + + // Additional Test 65: Final comprehensive stress test + void testFinalComprehensiveStressTest() + { + LoggerPtr root = hierarchy->getRootLogger(); + std::vector<LoggerPtr> allLoggers; + + // Create complex hierarchy + std::string bases[] = {"com", "org", "net", "edu"}; + std::string mids[] = {"example", "apache", "test", "demo"}; + std::string ends[] = {"app", "service", "module", "component"}; + + for (size_t i = 0; i < sizeof(bases)/sizeof(bases[0]); ++i) + { + for (size_t j = 0; j < sizeof(mids)/sizeof(mids[0]); ++j) + { + for (size_t k = 0; k < sizeof(ends)/sizeof(ends[0]); ++k) + { + std::ostringstream oss; + oss << bases[i] << "." << mids[j] << "." << ends[k]; + LoggerPtr logger = hierarchy->getLogger(oss.str()); + allLoggers.push_back(logger); + } + } + } + + // Set root level + root->setLevel(Level::getWarn()); + + // Verify all loggers + for (size_t i = 0; i < allLoggers.size(); ++i) + { + assertThresholdConsistent(allLoggers[i]); + assertThresholdIs(Level::getWarn(), allLoggers[i]); + } + + // Set levels on some base loggers + LoggerPtr com = hierarchy->getLogger("com"); + LoggerPtr org = hierarchy->getLogger("org"); + com->setLevel(Level::getInfo()); + org->setLevel(Level::getDebug()); + + // Verify all loggers again + for (size_t i = 0; i < allLoggers.size(); ++i) + { + assertThresholdConsistent(allLoggers[i]); + } + + // Set levels on some mid-level loggers + LoggerPtr comExample = hierarchy->getLogger("com.example"); + LoggerPtr orgApache = hierarchy->getLogger("org.apache"); + comExample->setLevel(Level::getTrace()); + orgApache->setLevel(Level::getError()); + + // Verify all loggers again + for (size_t i = 0; i < allLoggers.size(); ++i) + { + assertThresholdConsistent(allLoggers[i]); + } + + // Set some to null + com->setLevel(LevelPtr()); + + // Verify all loggers again + for (size_t i = 0; i < allLoggers.size(); ++i) + { + assertThresholdConsistent(allLoggers[i]); + } + + // Change root level + root->setLevel(Level::getFatal()); + + // Final verification + for (size_t i = 0; i < allLoggers.size(); ++i) + { + assertThresholdConsistent(allLoggers[i]); + } + + // Verify specific expected values + LoggerPtr comExampleApp = hierarchy->getLogger("com.example.app"); + assertThresholdConsistent(comExampleApp); + assertThresholdIs(Level::getTrace(), comExampleApp); + + LoggerPtr orgApacheTest = hierarchy->getLogger("org.apache.test"); + assertThresholdConsistent(orgApacheTest); + assertThresholdIs(Level::getError(), orgApacheTest); + + LoggerPtr netExampleApp = hierarchy->getLogger("net.example.app"); + assertThresholdConsistent(netExampleApp); + assertThresholdIs(Level::getFatal(), netExampleApp); + } +}; + +LOGUNIT_TEST_SUITE_REGISTRATION(LoggerThresholdConsistencyTest); diff --git a/src/test/cpp/logunit.h b/src/test/cpp/logunit.h index cdd7ac66..b86555a3 100644 --- a/src/test/cpp/logunit.h +++ b/src/test/cpp/logunit.h @@ -263,6 +263,7 @@ class RegisterDisabledSuite #define LOGUNIT_ASSERT( x) { if (!(x)) throw LogUnit::AssertException(true, #x, __LINE__); } +#define LOGUNIT_ASSERT_MESSAGE(x, msg) { if (!(x)) throw LogUnit::AssertException(msg, __LINE__); } #define LOGUNIT_ASSERT_SRCL(x, srcLine) { if (!(x)) throw LogUnit::AssertException(true, #x, srcLine); } #define LOGUNIT_ASSERT_EQUAL( expected, actual) assertEquals(expected, actual, #expected, #actual, __LINE__) #define LOGUNIT_ASSERT_EQUAL_SRCL( expected, actual, srcLine) assertEquals(expected, actual, #expected, #actual, srcLine)
