< Summary - Helper.Tests

Information
Class: Application.Helper.ConsoleApp
Assembly: Application.Helper
File(s): D:\a\NuGetPackages\NuGetPackages\src\Helper\Application.Helper\ConsoleApp.cs
Tag: 3_8508158812
Line coverage
100%
Covered lines: 110
Uncovered lines: 0
Coverable lines: 110
Total lines: 247
Line coverage: 100%
Branch coverage
86%
Covered branches: 62
Total branches: 72
Branch coverage: 86.1%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_ConfigFile()100%11100%
get_Title()100%11100%
get_HelpRequest()100%11100%
get_DebugMode()100%11100%
get_ElapsedTime()100%11100%
get_IsUnitTest()100%11100%
.ctor(...)100%22100%
GetAppConfigFile(...)66.66%66100%
GetAssemblyAttribute(...)100%22100%
SetStartTime(...)100%22100%
SetEndTime(...)91.66%1212100%
FormatTitle(...)60%1010100%
ShowProgramInfo(...)75%1212100%
StartApp()100%22100%
StartApp(...)100%88100%
ShowProgramInfo()100%11100%
StopApp(...)100%66100%
FormatTitleLine(...)100%66100%
ResumeElapsed()100%22100%
SuspendElapsed()100%22100%

File(s)

D:\a\NuGetPackages\NuGetPackages\src\Helper\Application.Helper\ConsoleApp.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Diagnostics;
 4using System.IO;
 5using System.Linq;
 6using System.Reflection;
 7
 8namespace Application.Helper
 9{
 10  /// <summary>Helper class for Console Applications.</summary>
 11  public class ConsoleApp
 12  {
 13    #region Properties
 14
 15    /// <summary>Gets the name of the current application configuration file.</summary>
 216    public string ConfigFile { get; }
 17
 18    /// <summary>Gets the application title.</summary>
 1919    public string Title { get; private set; }
 20
 21    /// <summary>Indicates whether execution help has been requested.</summary>
 222    public bool HelpRequest { get; private set; }
 23
 24    /// <summary>Indicates whether a debugger is attached to the process.</summary>
 3025    public bool DebugMode { get; }
 26
 27    /// <summary>Gets the total elapsed time measured.</summary>
 1228    public TimeSpan ElapsedTime => _stopWatch.Elapsed;
 29
 30    /// <summary>Sets whether this is running as a unit test.</summary>
 4131    public bool IsUnitTest { private get; set; } = false;
 32
 33    #endregion
 34
 35    #region Constructor
 36
 37    /// <summary>Stop watch to calculate elapse time.</summary>
 1738    private readonly Stopwatch _stopWatch = new Stopwatch();
 39
 40    private bool _started;
 41
 42    /// <summary>Creates a new instance of the ConsoleApp class.</summary>
 43    /// <param name="configFile">Configuration file name.<br/>
 44    /// The default is "appsettings.json"</param>
 45    /// <param name="detectDebugMode">Detect if a debugger is attached or not.<br/>
 46    /// The default is <see langword="true"/></param>
 47    /// <exception cref="ArgumentException">Thrown when one of the arguments provided to a method is not valid.</excepti
 48    /// <exception cref="TypeLoadException">Thrown when type-loading failures occur.</exception>
 1749    public ConsoleApp( string configFile = "appsettings.json", bool detectDebugMode = true )
 1750    {
 1751      ConfigFile = GetAppConfigFile( configFile );
 1752      Title = FormatTitle( Assembly.GetEntryAssembly() );
 1753      DebugMode = !detectDebugMode || Debugger.IsAttached;
 1754    }
 55
 56    #endregion
 57
 58    #region Private Methods
 59
 60    private static string GetAppConfigFile( string configFile )
 1761    {
 1762      string retValue = configFile;
 1963      if( File.Exists( retValue ) ) { return retValue; }
 64
 65      // Get the name of the executable
 1666      retValue = Path.GetFileName( Assembly.GetEntryAssembly().Location );
 67
 68      // Check for XML config file
 1669      retValue = Path.ChangeExtension( retValue, ".config" );
 1670      if( File.Exists( retValue ) ) { return retValue; }
 71
 72      // Check for JSON config file
 1673      retValue = Path.ChangeExtension( retValue, ".json" );
 1674      if( File.Exists( retValue ) ) { return retValue; }
 75
 1676      return string.Empty;
 1777    }
 78
 79    private static T GetAssemblyAttribute<T>( ICustomAttributeProvider assembly ) where T : Attribute
 3680    {
 3681      object[] attributes = assembly.GetCustomAttributes( typeof( T ), false );
 3682      return attributes.Length == 0 ? null : attributes.OfType<T>().SingleOrDefault();
 3683    }
 84
 85    private static void SetStartTime( ConsoleApp app )
 1686    {
 2687      if( !app.DebugMode ) { return; }
 88
 89      // Log the start time
 1190      Console.WriteLine( @"Start..: " + DateTime.Now.ToString( @"HH:mm:ss.fffffff" ) );
 1191      Console.WriteLine();
 1692    }
 93
 94    private static void SetEndTime( ConsoleApp app, bool result, bool unitTest )
 1395    {
 5296      if( app._stopWatch.IsRunning ) { app.SuspendElapsed(); }
 97
 1598      if( !app.DebugMode ) return;
 99
 100      // Log the completion and elapsed times
 11101      string exitCode = Environment.ExitCode > 0 ? " with exit code " + Environment.ExitCode : string.Empty;
 11102      Console.WriteLine();
 11103      Console.WriteLine( @"Runtime: " + app.ElapsedTime );
 11104      Console.WriteLine( @"Result.: " + ( result ? "Success" : "Failed" ) + exitCode );
 11105      if( !Environment.UserInteractive ) return;
 106
 11107      Console.WriteLine( string.Empty );
 11108      Console.Write( @"Press any key to continue . . . " );
 11109      if( !unitTest ) { _ = Console.Read(); }
 13110    }
 111
 112    private static string FormatTitle( Assembly assembly )
 17113    {
 17114      AssemblyTitleAttribute titleAttr = GetAssemblyAttribute<AssemblyTitleAttribute>( assembly );
 17115      string titleStr = titleAttr?.Title.Trim() ?? string.Empty;
 116
 117      // Get the file version
 17118      string versionStr = null;
 17119      AssemblyFileVersionAttribute versionAttr = GetAssemblyAttribute<AssemblyFileVersionAttribute>( assembly );
 68120      if( null != versionAttr ) { versionStr = versionAttr.Version.Trim(); }
 121
 122      // If no file version get it from the full name
 17123      if( null == versionStr ) { versionStr = assembly.GetName().Version.ToString(); }
 124
 17125      return versionStr.Length > 0 ? (titleStr + $" [Version {versionStr}]").Trim() : titleStr;
 17126    }
 127
 128    private void ShowProgramInfo( ICustomAttributeProvider assembly )
 1129    {
 130      // Add the description to the title
 1131      AssemblyDescriptionAttribute descAttr = GetAssemblyAttribute<AssemblyDescriptionAttribute>( assembly );
 1132      string descStr = descAttr?.Description.Trim() ?? string.Empty;
 1133      string titleStr = descStr.Length > 0 ? ( Title + $" {descStr}" ).Trim() : Title;
 134
 135      // Display the title line
 1136      if( titleStr.Length > 0 )
 1137      {
 1138        Console.WriteLine( titleStr );
 1139      }
 140
 141      // Display the copyright line
 1142      AssemblyCopyrightAttribute copyAttr = GetAssemblyAttribute<AssemblyCopyrightAttribute>( assembly );
 1143      if( copyAttr != null && copyAttr.Copyright.Length > 0 )
 1144      {
 1145        Console.WriteLine( copyAttr.Copyright );
 1146      }
 147
 1148      Console.WriteLine();
 1149    }
 150
 151    #endregion
 152
 153    #region Public Methods
 154
 155    /// <summary>Start the console application.</summary>
 156    /// <returns><see langword="true"/> if the application has already been started.</returns>
 157    public bool StartApp()
 19158    {
 159      // Check whether the application has already been started
 25160      if( _started ) { return true; }
 16161      _started = true;
 162
 163      // Show the application start time and start the stopwatch
 16164      SetStartTime( this );
 16165      ResumeElapsed();
 166
 16167      return false;
 19168    }
 169
 170    /// <summary>Start the console application.</summary>
 171    /// <param name="args">Collection of command-line arguments.</param>
 172    public void StartApp( IReadOnlyList<string> args )
 4173    {
 174      // Check whether the application has already been started
 6175      if( StartApp() ) { return; }
 176
 177      // Check for command line help request
 3178      args = args ?? new List<string>();
 3179      if( args.Count > 0 && args[0].Contains( "?" ) )
 1180      {
 1181        ShowProgramInfo();
 182
 183        // Set the flag to indicate help has been requested
 1184        HelpRequest = true;
 1185      }
 4186    }
 187
 188    /// <summary>Output the program information to the Console.</summary>
 189    /// <remarks>This method can be overridden in a derived class to provide specific
 190    /// information about the program when the command line help request is made using
 191    /// ? anywhere in the first argument.</remarks>
 192    /// <exception cref="TypeLoadException">Thrown when type-loading failures occur.</exception>
 193    public virtual void ShowProgramInfo()
 1194    {
 1195      ShowProgramInfo( Assembly.GetEntryAssembly() );
 1196    }
 197
 198    /// <summary>Stops the application and sets the exit code.</summary>
 199    /// <param name="result">Execution result, <see langword="false"/> sets the exit code to 1.</param>
 200    public void StopApp( bool result = true )
 15201    {
 202      // Check whether the application has already been stopped
 19203      if( !_started ) { return; }
 13204      _started = false;
 205
 206      // Set the return code if it is not already set
 13207      if( 0 == Environment.ExitCode )
 12208      {
 12209        Environment.ExitCode = result ? 0 : 1;
 12210      }
 211
 212      // Set the application stop variables
 13213      SetEndTime( this, result, IsUnitTest );
 15214    }
 215
 216    /// <summary>Formats a title line to be logged.</summary>
 217    /// <param name="text">Program title.</param>
 218    /// <param name="maxWidth">Maximum line width, default is 80 characters.</param>
 219    /// <returns>String containing the maximum width title.</returns>
 220    public string FormatTitleLine( string text, int maxWidth = 80 )
 4221    {
 4222      text = text ?? string.Empty;
 6223      if( text.Length >= maxWidth ) { return text; }
 224
 225      // Center the title and pad width '-' characters
 3226      int filler = ( maxWidth - text.Length ) / 2;
 3227      string padding = new string( '-', filler );
 6228      if( text.Length + filler * 2 != maxWidth ) { text += "-"; }
 229
 3230      return padding + text + padding;
 4231    }
 232
 233    /// <summary>Resumes measuring elapsed time for an interval.</summary>
 234    public void ResumeElapsed()
 16235    {
 64236      if( !_stopWatch.IsRunning ) { _stopWatch.Start(); }
 16237    }
 238
 239    /// <summary>Suspends measuring elapsed time for an interval.</summary>
 240    public void SuspendElapsed()
 13241    {
 52242      if( _stopWatch.IsRunning ) { _stopWatch.Stop(); }
 13243    }
 244
 245    #endregion
 246  }
 247}