diff --git a/src/log4net.Tests/Core/LevelMapTest.cs b/src/log4net.Tests/Core/LevelMapTest.cs index b741cf92..70d80a8b 100644 --- a/src/log4net.Tests/Core/LevelMapTest.cs +++ b/src/log4net.Tests/Core/LevelMapTest.cs @@ -18,21 +18,20 @@ #endregion using log4net.Core; -using log4net.Tests.Layout; using NUnit.Framework; namespace log4net.Tests.Core { /// - /// Used for internal unit testing the class. + /// Used for internal unit testing the class. /// - /// - /// Used for internal unit testing the class. - /// [TestFixture] - public class LevelMapTest + public sealed class LevelMapTest { + /// + /// Tests the creation of a and calling its method + /// [Test] public void LevelMapCreateClear() { diff --git a/src/log4net.Tests/Core/LevelTest.cs b/src/log4net.Tests/Core/LevelTest.cs new file mode 100644 index 00000000..707e5d8e --- /dev/null +++ b/src/log4net.Tests/Core/LevelTest.cs @@ -0,0 +1,74 @@ +#region Apache License +// +// 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. +// +#endregion + +using System; +using System.Runtime.CompilerServices; +using log4net.Core; + +using NUnit.Framework; + +namespace log4net.Tests.Core +{ + /// + /// Used for internal unit testing the class. + /// + [TestFixture] + public sealed class LevelTest + { + + /// + /// Tests the comparison between two s + /// + [Test] + public void LevelCompare() + { + Level? nullLevel = null; + int? nullInt = null; + Compare(nullInt, nullInt, nullLevel, nullLevel); + Compare(nullInt, Level.Verbose.Value, nullLevel, Level.Verbose); + Compare(Level.Verbose.Value, nullInt, Level.Verbose, nullLevel); + Compare(Level.Verbose.Value, Level.Verbose.Value, Level.Verbose, Level.Verbose); + Compare(Level.Debug.Value, Level.Verbose.Value, Level.Debug, Level.Verbose); + } + + private static void Compare(int? leftInt, int? rightInt, Level? left, Level? right, + [CallerArgumentExpression(nameof(left))] string leftName = "", + [CallerArgumentExpression(nameof(right))] string rightName = "") + { + Assert.AreEqual(leftInt < rightInt, left < right, "{0} < {1}", leftName, rightName); + Assert.AreEqual(leftInt > rightInt, left > right, "{0} > {1}", leftName, rightName); + Assert.AreEqual(leftInt <= rightInt, left <= right, "{0} <= {1}", leftName, rightName); + Assert.AreEqual(leftInt >= rightInt, left >= right, "{0} >= {1}", leftName, rightName); + Assert.AreEqual(leftInt == rightInt, left == right, "{0} == {1}", leftName, rightName); + Assert.AreEqual(leftInt != rightInt, left != right, "{0} != {1}", leftName, rightName); + Assert.AreEqual(leftInt?.Equals(rightInt), left?.Equals(right), "{0}?.Equals({1})", leftName, rightName); + if (leftInt is not null) + { + if (rightInt is not null) + { + Assert.AreEqual(leftInt?.CompareTo(rightInt), left?.CompareTo(right!), "{0}?.CompareTo({1})", leftName, rightName); + } + else + { + Assert.Throws(() => left!.CompareTo(right!)); + } + } + } + } +} \ No newline at end of file diff --git a/src/log4net.Tests/log4net.Tests.csproj b/src/log4net.Tests/log4net.Tests.csproj index dfd50f41..6392af70 100644 --- a/src/log4net.Tests/log4net.Tests.csproj +++ b/src/log4net.Tests/log4net.Tests.csproj @@ -13,6 +13,9 @@ CS8032 + + + diff --git a/src/log4net/Core/Level.cs b/src/log4net/Core/Level.cs index 47fc02de..4c0c99f8 100644 --- a/src/log4net/Core/Level.cs +++ b/src/log4net/Core/Level.cs @@ -20,523 +20,468 @@ using System; using System.Runtime.Serialization; using System.Security; -using System.Xml.Linq; using log4net.Util; -namespace log4net.Core +namespace log4net.Core; + +/// +/// Defines the default set of levels recognized by the system. +/// +/// +/// +/// Each has an associated . +/// +/// +/// Levels have a numeric that defines the relative +/// ordering between levels. Two Levels with the same +/// are deemed to be equivalent. +/// +/// +/// The levels that are recognized by log4net are set for each +/// and each repository can have different levels defined. The levels are stored +/// in the on the repository. Levels are +/// looked up by name from the . +/// +/// +/// When logging at level INFO the actual level used is not but +/// the value of LoggerRepository.LevelMap["INFO"]. The default value for this is +/// , but this can be changed by reconfiguring the level map. +/// +/// +/// Each level has a in addition to its . The +/// is the string that is written into the output log. By default +/// the display name is the same as the level name, but this can be used to alias levels +/// or to localize the log output. +/// +/// +/// Some of the predefined levels recognized by the system are: +/// +/// +/// +/// . +/// +/// +/// . +/// +/// +/// . +/// +/// +/// . +/// +/// +/// . +/// +/// +/// . +/// +/// +/// . +/// +/// +/// +/// Nicko Cadell +/// Gert Driesen +[Serializable] +public class Level : IComparable, ISerializable, IEquatable, IComparable { /// - /// Defines the default set of levels recognized by the system. + /// Constructor /// + /// Integer value for this level, higher values represent more severe levels. + /// The string name of this level. + /// The display name for this level. This may be localized or otherwise different from the name /// /// - /// Each has an associated . + /// Initializes a new instance of the class with + /// the specified level name and value. /// + /// + public Level(int level, string levelName, string displayName) + { + Value = level; + Name = string.Intern(levelName.EnsureNotNull()); + DisplayName = displayName.EnsureNotNull(); + } + + /// + /// Constructor + /// + /// Integer value for this level, higher values represent more severe levels. + /// The string name of this level. + /// /// - /// Levels have a numeric that defines the relative - /// ordering between levels. Two Levels with the same - /// are deemed to be equivalent. + /// Initializes a new instance of the class with + /// the specified level name and value. /// + /// + public Level(int level, string levelName) + : this(level, levelName, levelName) + { } + + /// + /// Serialization constructor + /// + /// The that holds the serialized object data. + /// The that contains contextual information about the source or destination. + /// /// - /// The levels that are recognized by log4net are set for each - /// and each repository can have different levels defined. The levels are stored - /// in the on the repository. Levels are - /// looked up by name from the . + /// Initializes a new instance of the class + /// with serialized data. /// + /// + protected Level(SerializationInfo info, StreamingContext context) + { + // Use member names from log4net 2.x implicit serialzation for cross-version compat. + Value = info.GetInt32("m_levelValue"); + Name = info.GetString("m_levelName") ?? string.Empty; + DisplayName = info.GetString("m_levelDisplayName") ?? string.Empty; + } + + /// + /// Gets the name of this level. + /// + /// + /// The name of this level. + /// + /// /// - /// When logging at level INFO the actual level used is not but - /// the value of LoggerRepository.LevelMap["INFO"]. The default value for this is - /// , but this can be changed by reconfiguring the level map. + /// Gets the name of this level. /// + /// + public string Name { get; } + + /// + /// Gets the value of this level. + /// + public int Value { get; } + + /// + /// Gets the display name of this level. + /// + public string DisplayName { get; } + + /// + /// Returns the representation of the current + /// . + /// + /// + /// A representation of the current . + /// + /// /// - /// Each level has a in addition to its . The - /// is the string that is written into the output log. By default - /// the display name is the same as the level name, but this can be used to alias levels - /// or to localize the log output. + /// Returns the level . /// + /// + public override string ToString() => Name; + + /// + public override bool Equals(object? o) => o is Level level && Equals(level); + + /// + /// Compares levels. + /// + /// The object to compare against. + /// if the objects are equal. + public bool Equals(Level? other) => other?.Value == Value; + + /// + /// Returns a hash code + /// + /// A hash code for the current . + /// /// - /// Some of the predefined levels recognized by the system are: + /// Returns a hash code suitable for use in hashing algorithms and data + /// structures like a hash table. /// - /// - /// - /// . - /// + /// + /// Returns the hash code of the level . + /// + /// + public override int GetHashCode() => Value; + + /// + public int CompareTo(object? r) => Compare(this, r.EnsureIs()); + + /// + /// Compares this instance to a specified object and returns an + /// indication of their relative values. + /// + /// A instance or to compare with this instance. + /// + /// A 32-bit signed integer that indicates the relative order of the + /// values compared. The return value has these meanings: + /// + /// + /// Value + /// Meaning + /// /// - /// . + /// Less than zero + /// This instance is less than . /// /// - /// . + /// Zero + /// This instance is equal to . /// /// - /// . + /// Greater than zero + /// + /// This instance is greater than . + /// -or- + /// is . + /// /// + /// + /// + /// + /// + /// must be an instance of + /// or ; otherwise, an exception is thrown. + /// + /// + public int CompareTo(Level other) => Compare(this, other.EnsureNotNull()); + + /// + /// Serializes this object into the provided. + /// + /// The to populate with data. + /// The destination for this serialization. + [SecurityCritical] + [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, + SerializationFormatter = true)] + public virtual void GetObjectData(SerializationInfo info, StreamingContext context) + { + // Use member names from log4net 2.x implicit serialzation for cross-version compat. + info.AddValue("m_levelValue", Value); + info.AddValue("m_levelName", Name); + info.AddValue("m_levelDisplayName", DisplayName); + } + + /// + /// Returns a value indicating whether a specified + /// is greater than another specified . + /// + /// A + /// A + /// + /// if is greater than + /// ; otherwise, . + /// + public static bool operator >(Level? l, Level? r) => l?.Value > r?.Value; + + /// + /// Returns a value indicating whether a specified + /// is less than another specified . + /// + /// A + /// A + /// + /// if is less than + /// ; otherwise, . + /// + public static bool operator <(Level? l, Level? r) => l?.Value < r?.Value; + + /// + /// Returns a value indicating whether a specified + /// is greater than or equal to another specified . + /// + /// A + /// A + /// + /// if is greater than or equal to + /// ; otherwise, . + /// + public static bool operator >=(Level? l, Level? r) => l?.Value >= r?.Value; + + /// + /// Returns a value indicating whether a specified + /// is less than or equal to another specified . + /// + /// A + /// A + /// + /// if is less than or equal to + /// ; otherwise, . + /// + public static bool operator <=(Level? l, Level? r) => l?.Value <= r?.Value; + + /// + /// Returns a value indicating whether two specified + /// objects have the same value. + /// + /// A or . + /// A or . + /// + /// if the value of is the same as the + /// value of ; otherwise, . + /// + public static bool operator ==(Level? l, Level? r) => l?.Value == r?.Value; + + /// + /// Returns a value indicating whether two specified + /// objects have different values. + /// + /// A or . + /// A or . + /// + /// if the value of is different from + /// the value of ; otherwise, . + /// + public static bool operator !=(Level? l, Level? r) => !(l == r); + + /// + /// Compares two specified instances. + /// + /// The first to compare. + /// The second to compare. + /// + /// A 32-bit signed integer that indicates the relative order of the + /// two values compared. The return value has these meanings: + /// + /// + /// Value + /// Meaning + /// /// - /// . + /// Less than zero + /// is less than . /// /// - /// . + /// Zero + /// is equal to . /// /// - /// . + /// Greater than zero + /// is greater than . /// /// - /// - /// Nicko Cadell - /// Gert Driesen - [Serializable] - public class Level : IComparable, ISerializable + /// + public static int Compare(Level? l, Level? r) { - /// - /// Constructor - /// - /// Integer value for this level, higher values represent more severe levels. - /// The string name of this level. - /// The display name for this level. This may be localized or otherwise different from the name - /// - /// - /// Initializes a new instance of the class with - /// the specified level name and value. - /// - /// - public Level(int level, string levelName, string displayName) + if (ReferenceEquals(l, r)) { - Value = level; - Name = string.Intern(levelName.EnsureNotNull()); - DisplayName = displayName.EnsureNotNull(); + return 0; } - /// - /// Constructor - /// - /// Integer value for this level, higher values represent more severe levels. - /// The string name of this level. - /// - /// - /// Initializes a new instance of the class with - /// the specified level name and value. - /// - /// - public Level(int level, string levelName) - : this(level, levelName, levelName) - { } - - /// - /// Serialization constructor - /// - /// The that holds the serialized object data. - /// The that contains contextual information about the source or destination. - /// - /// - /// Initializes a new instance of the class - /// with serialized data. - /// - /// - protected Level(SerializationInfo info, StreamingContext context) + if (l is null && r is null) { - // Use member names from log4net 2.x implicit serialzation for cross-version compat. - Value = info.GetInt32("m_levelValue"); - Name = info.GetString("m_levelName") ?? string.Empty; - DisplayName = info.GetString("m_levelDisplayName") ?? string.Empty; + return 0; } - - /// - /// Gets the name of this level. - /// - /// - /// The name of this level. - /// - /// - /// - /// Gets the name of this level. - /// - /// - public string Name { get; } - - /// - /// Gets the value of this level. - /// - public int Value { get; } - - /// - /// Gets the display name of this level. - /// - public string DisplayName { get; } - - /// - /// Returns the representation of the current - /// . - /// - /// - /// A representation of the current . - /// - /// - /// - /// Returns the level . - /// - /// - public override string ToString() => Name; - - /// - /// Compares levels. - /// - /// The object to compare against. - /// true if the objects are equal. - /// - /// - /// Compares the levels of instances, and - /// defers to base class if the target object is not a - /// instance. - /// - /// - public override bool Equals(object? o) + if (l is null) { - if (o is Level otherLevel) - { - return Value == otherLevel.Value; - } - return base.Equals(o); + return -1; } - - /// - /// Returns a hash code - /// - /// A hash code for the current . - /// - /// - /// Returns a hash code suitable for use in hashing algorithms and data - /// structures like a hash table. - /// - /// - /// Returns the hash code of the level . - /// - /// - public override int GetHashCode() => Value; - - /// - /// Compares this instance to a specified object and returns an - /// indication of their relative values. - /// - /// A instance or to compare with this instance. - /// - /// A 32-bit signed integer that indicates the relative order of the - /// values compared. The return value has these meanings: - /// - /// - /// Value - /// Meaning - /// - /// - /// Less than zero - /// This instance is less than . - /// - /// - /// Zero - /// This instance is equal to . - /// - /// - /// Greater than zero - /// - /// This instance is greater than . - /// -or- - /// is . - /// - /// - /// - /// - /// - /// - /// must be an instance of - /// or ; otherwise, an exception is thrown. - /// - /// - /// is not a . - public int CompareTo(object? r) + if (r is null) { - if (r is Level target) - { - return Compare(this, target); - } - throw new ArgumentException($"Parameter: r, Value: [{r}] is not an instance of Level"); + return 1; } - /// - /// Serializes this object into the provided. - /// - /// The to populate with data. - /// The destination for this serialization. - [SecurityCritical] - [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, - SerializationFormatter = true)] - public virtual void GetObjectData(SerializationInfo info, StreamingContext context) - { - // Use member names from log4net 2.x implicit serialzation for cross-version compat. - info.AddValue("m_levelValue", Value); - info.AddValue("m_levelName", Name); - info.AddValue("m_levelDisplayName", DisplayName); - } + return l.Value.CompareTo(r.Value); + } - /// - /// Returns a value indicating whether a specified - /// is greater than another specified . - /// - /// A - /// A - /// - /// true if is greater than - /// ; otherwise, false. - /// - /// - /// - /// Compares two levels. - /// - /// - public static bool operator >(Level l, Level r) - { - return l.Value > r.Value; - } + /// + /// The level designates a higher level than all the rest. + /// + public static readonly Level Off = new(int.MaxValue, "OFF"); - /// - /// Returns a value indicating whether a specified - /// is less than another specified . - /// - /// A - /// A - /// - /// true if is less than - /// ; otherwise, false. - /// - /// - /// - /// Compares two levels. - /// - /// - public static bool operator <(Level l, Level r) - { - return l.Value < r.Value; - } + /// + /// The level designates very severe error events. + /// System unusable, emergencies. + /// + public static readonly Level Log4Net_Debug = new(120000, "log4net:DEBUG"); - /// - /// Returns a value indicating whether a specified - /// is greater than or equal to another specified . - /// - /// A - /// A - /// - /// true if is greater than or equal to - /// ; otherwise, false. - /// - /// - /// - /// Compares two levels. - /// - /// - public static bool operator >=(Level l, Level r) - { - return l.Value >= r.Value; - } + /// + /// The level designates very severe error events. + /// System unusable, emergencies. + /// + public static readonly Level Emergency = new(120000, "EMERGENCY"); - /// - /// Returns a value indicating whether a specified - /// is less than or equal to another specified . - /// - /// A - /// A - /// - /// true if is less than or equal to - /// ; otherwise, false. - /// - public static bool operator <=(Level l, Level r) - { - return l.Value <= r.Value; - } + /// + /// The level designates very severe error events + /// that will presumably lead the application to abort. + /// + public static readonly Level Fatal = new(110000, "FATAL"); - /// - /// Returns a value indicating whether two specified - /// objects have the same value. - /// - /// A or . - /// A or . - /// - /// true if the value of is the same as the - /// value of ; otherwise, false. - /// - public static bool operator ==(Level? l, Level? r) - { - if (l is not null && r is not null) - { - return l.Value == r.Value; - } - return ReferenceEquals(l, r); - } + /// + /// The level designates very severe error events. + /// Take immediate action, alerts. + /// + public static readonly Level Alert = new(100000, "ALERT"); - /// - /// Returns a value indicating whether two specified - /// objects have different values. - /// - /// A or . - /// A or . - /// - /// true if the value of is different from - /// the value of ; otherwise, false. - /// - public static bool operator !=(Level l, Level r) - { - return !(l == r); - } + /// + /// The level designates very severe error events. + /// Critical condition, critical. + /// + public static readonly Level Critical = new(90000, "CRITICAL"); - /// - /// Compares two specified instances. - /// - /// The first to compare. - /// The second to compare. - /// - /// A 32-bit signed integer that indicates the relative order of the - /// two values compared. The return value has these meanings: - /// - /// - /// Value - /// Meaning - /// - /// - /// Less than zero - /// is less than . - /// - /// - /// Zero - /// is equal to . - /// - /// - /// Greater than zero - /// is greater than . - /// - /// - /// - public static int Compare(Level? l, Level? r) - { - if (ReferenceEquals(l, r)) - { - return 0; - } - - if (l is null && r is null) - { - return 0; - } - if (l is null) - { - return -1; - } - if (r is null) - { - return 1; - } - - return l.Value.CompareTo(r.Value); - } + /// + /// The level designates very severe error events. + /// + public static readonly Level Severe = new(80000, "SEVERE"); - /// - /// The level designates a higher level than all the rest. - /// - public static readonly Level Off = new(int.MaxValue, "OFF"); - - /// - /// The level designates very severe error events. - /// System unusable, emergencies. - /// - public static readonly Level Log4Net_Debug = new(120000, "log4net:DEBUG"); - - /// - /// The level designates very severe error events. - /// System unusable, emergencies. - /// - public static readonly Level Emergency = new(120000, "EMERGENCY"); - - /// - /// The level designates very severe error events - /// that will presumably lead the application to abort. - /// - public static readonly Level Fatal = new(110000, "FATAL"); - - /// - /// The level designates very severe error events. - /// Take immediate action, alerts. - /// - public static readonly Level Alert = new(100000, "ALERT"); - - /// - /// The level designates very severe error events. - /// Critical condition, critical. - /// - public static readonly Level Critical = new(90000, "CRITICAL"); - - /// - /// The level designates very severe error events. - /// - public static readonly Level Severe = new(80000, "SEVERE"); - - /// - /// The level designates error events that might - /// still allow the application to continue running. - /// - public static readonly Level Error = new(70000, "ERROR"); - - /// - /// The level designates potentially harmful - /// situations. - /// - public static readonly Level Warn = new(60000, "WARN"); - - /// - /// The level designates informational messages - /// that highlight the progress of the application at the highest level. - /// - public static readonly Level Notice = new(50000, "NOTICE"); - - /// - /// The level designates informational messages that - /// highlight the progress of the application at coarse-grained level. - /// - public static readonly Level Info = new(40000, "INFO"); - - /// - /// The level designates fine-grained informational - /// events that are most useful to debug an application. - /// - public static readonly Level Debug = new(30000, "DEBUG"); - - /// - /// The level designates fine-grained informational - /// events that are most useful to debug an application. - /// - public static readonly Level Fine = new(30000, "FINE"); - - /// - /// The level designates fine-grained informational - /// events that are most useful to debug an application. - /// - public static readonly Level Trace = new(20000, "TRACE"); - - /// - /// The level designates fine-grained informational - /// events that are most useful to debug an application. - /// - public static readonly Level Finer = new(20000, "FINER"); - - /// - /// The level designates fine-grained informational - /// events that are most useful to debug an application. - /// - public static readonly Level Verbose = new(10000, "VERBOSE"); - - /// - /// The level designates fine-grained informational - /// events that are most useful to debug an application. - /// - public static readonly Level Finest = new(10000, "FINEST"); - - /// - /// The level designates the lowest level possible. - /// - public static readonly Level All = new(int.MinValue, "ALL"); - } + /// + /// The level designates error events that might + /// still allow the application to continue running. + /// + public static readonly Level Error = new(70000, "ERROR"); + + /// + /// The level designates potentially harmful + /// situations. + /// + public static readonly Level Warn = new(60000, "WARN"); + + /// + /// The level designates informational messages + /// that highlight the progress of the application at the highest level. + /// + public static readonly Level Notice = new(50000, "NOTICE"); + + /// + /// The level designates informational messages that + /// highlight the progress of the application at coarse-grained level. + /// + public static readonly Level Info = new(40000, "INFO"); + + /// + /// The level designates fine-grained informational + /// events that are most useful to debug an application. + /// + public static readonly Level Debug = new(30000, "DEBUG"); + + /// + /// The level designates fine-grained informational + /// events that are most useful to debug an application. + /// + public static readonly Level Fine = new(30000, "FINE"); + + /// + /// The level designates fine-grained informational + /// events that are most useful to debug an application. + /// + public static readonly Level Trace = new(20000, "TRACE"); + + /// + /// The level designates fine-grained informational + /// events that are most useful to debug an application. + /// + public static readonly Level Finer = new(20000, "FINER"); + + /// + /// The level designates fine-grained informational + /// events that are most useful to debug an application. + /// + public static readonly Level Verbose = new(10000, "VERBOSE"); + + /// + /// The level designates fine-grained informational + /// events that are most useful to debug an application. + /// + public static readonly Level Finest = new(10000, "FINEST"); + + /// + /// The level designates the lowest level possible. + /// + public static readonly Level All = new(int.MinValue, "ALL"); }