File: src\libraries\System.Private.CoreLib\src\System\Diagnostics\DebugProvider.cs
Web Access
Project: src\src\coreclr\System.Private.CoreLib\System.Private.CoreLib.csproj (System.Private.CoreLib)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
// Do not remove this, it is needed to retain calls to these conditional methods in release builds
#define DEBUG
 
using System.Diagnostics.CodeAnalysis;
 
namespace System.Diagnostics
{
    /// <summary>
    /// Provides default implementation for Write and Fail methods in Debug class.
    /// </summary>
    public partial class DebugProvider
    {
        [DoesNotReturn]
        public virtual void Fail(string? message, string? detailMessage)
        {
            string stackTrace;
            try
            {
                stackTrace = new StackTrace(0, true).ToString(StackTrace.TraceFormat.Normal);
            }
            catch
            {
                stackTrace = "";
            }
            WriteAssert(stackTrace, message, detailMessage);
            FailCore(stackTrace, message, detailMessage, "Assertion failed.");
#pragma warning disable 8763 // "A method marked [DoesNotReturn] should not return."
        }
#pragma warning restore 8763
 
        internal void WriteAssert(string stackTrace, string? message, string? detailMessage)
        {
            WriteLine(SR.DebugAssertBanner + Environment.NewLineConst
                   + SR.DebugAssertShortMessage + Environment.NewLineConst
                   + message + Environment.NewLineConst
                   + SR.DebugAssertLongMessage + Environment.NewLineConst
                   + detailMessage + Environment.NewLineConst
                   + stackTrace);
        }
 
        public virtual void Write(string? message)
        {
            lock (s_lock)
            {
                if (message == null)
                {
                    WriteCore(string.Empty);
                    return;
                }
                if (_needIndent)
                {
                    message = GetIndentString() + message;
                    _needIndent = false;
                }
                WriteCore(message);
                if (message.EndsWith(Environment.NewLineConst, StringComparison.Ordinal))
                {
                    _needIndent = true;
                }
            }
        }
 
        public virtual void WriteLine(string? message)
        {
            Write(message + Environment.NewLineConst);
        }
 
        public virtual void OnIndentLevelChanged(int indentLevel) { }
 
        public virtual void OnIndentSizeChanged(int indentSize) { }
 
        private static readonly object s_lock = new object();
 
        private sealed class DebugAssertException : Exception
        {
            internal DebugAssertException(string? message, string? detailMessage, string? stackTrace) :
                base(Terminate(message) + Terminate(detailMessage) + stackTrace)
            {
            }
 
            private static string? Terminate(string? s)
            {
                if (s == null)
                    return s;
 
                s = s.Trim();
                if (s.Length > 0)
                    s += Environment.NewLineConst;
 
                return s;
            }
        }
 
        private bool _needIndent = true;
 
        private string? _indentString;
 
        private string GetIndentString()
        {
            int indentCount = Debug.IndentSize * Debug.IndentLevel;
            if (_indentString?.Length == indentCount)
            {
                return _indentString;
            }
            return _indentString = new string(' ', indentCount);
        }
 
        // internal and not readonly so that the tests can swap this out.
        internal static Action<string, string?, string?, string>? s_FailCore;
        internal static Action<string>? s_WriteCore;
    }
}