Best Xunit code snippet using Xunit.Runner.Common.ReaderWriterLockWrapper.WriteLock
DefaultRunnerReporterMessageHandler.cs
Source:DefaultRunnerReporterMessageHandler.cs  
...64		void AddExecutionOptions(65			string assemblyIdentifier,66			_ITestFrameworkExecutionOptions executionOptions)67		{68			using (ReaderWriterLockWrapper.WriteLock())69				executionOptionsByAssembly[assemblyIdentifier] = executionOptions;70		}71		/// <summary>72		/// Escapes text for display purposes.73		/// </summary>74		/// <param name="text">The text to be escaped</param>75		/// <returns>The escaped text</returns>76		protected virtual string Escape(string? text)77		{78			if (text == null)79				return string.Empty;80			return text.Replace("\r", "\\r").Replace("\n", "\\n").Replace("\t", "\\t").Replace("\0", "\\0");81		}82		/// <summary>83		/// Escapes multi-line text for display purposes, indenting on newlines.84		/// </summary>85		/// <param name="text">The text to be escaped</param>86		/// <param name="indent">The indent to use for multiple line text</param>87		/// <returns>The escaped text</returns>88		protected virtual string EscapeMultiLineIndent(89			string? text,90			string indent)91		{92			if (text == null)93				return string.Empty;94			return95				text96					.Replace("\r\n", "\n")97					.Replace("\r", "\n")98					.Replace("\n", $"{Environment.NewLine}{indent}")99					.Replace("\0", "\\0");100		}101		/// <summary>102		/// Gets the display name of a test assembly from a test assembly message.103		/// </summary>104		/// <param name="assembly">The test assembly</param>105		/// <returns>The assembly display name</returns>106		protected virtual string GetAssemblyDisplayName(XunitProjectAssembly assembly)107		{108			Guard.ArgumentNotNull(assembly);109			return assembly.AssemblyDisplayName;110		}111		/// <summary>112		/// Get the test framework options for the given assembly. If it cannot find them, then it113		/// returns a default set of options.114		/// </summary>115		/// <param name="assemblyFilename">The test assembly filename</param>116		protected _ITestFrameworkExecutionOptions GetExecutionOptions(string? assemblyFilename)117		{118			if (assemblyFilename != null)119				using (ReaderWriterLockWrapper.ReadLock())120					if (executionOptionsByAssembly.TryGetValue(assemblyFilename, out var result))121						return result;122			return defaultExecutionOptions;123		}124		/// <summary>125		/// Logs an error message to the logger.126		/// </summary>127		/// <param name="failureType">The type of the failure</param>128		/// <param name="errorMetadata">The failure information</param>129		protected void LogError(130			string failureType,131			_IErrorMetadata errorMetadata)132		{133			Guard.ArgumentNotNull(failureType);134			Guard.ArgumentNotNull(errorMetadata);135			var frameInfo = StackFrameInfo.FromErrorMetadata(errorMetadata);136			lock (Logger.LockObject)137			{138				Logger.LogError(frameInfo, $"    [{failureType}] {Escape(errorMetadata.ExceptionTypes.FirstOrDefault() ?? "(Unknown Exception Type)")}");139				foreach (var messageLine in ExceptionUtility.CombineMessages(errorMetadata).Split(new[] { Environment.NewLine }, StringSplitOptions.None))140					Logger.LogImportantMessage(frameInfo, $"      {messageLine}");141				LogStackTrace(frameInfo, ExceptionUtility.CombineStackTraces(errorMetadata));142			}143		}144		/// <summary>145		/// Logs a stack trace to the logger.146		/// </summary>147		protected virtual void LogStackTrace(148			StackFrameInfo frameInfo,149			string? stackTrace)150		{151			if (string.IsNullOrEmpty(stackTrace))152				return;153			Logger.LogMessage(frameInfo, "      Stack Trace:");154			foreach (var stackFrame in stackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.None))155				Logger.LogImportantMessage(frameInfo, $"        {StackFrameTransformer.TransformFrame(stackFrame, defaultDirectory)}");156		}157		/// <summary>158		/// Lots test output to the logger.159		/// </summary>160		protected virtual void LogOutput(161			StackFrameInfo frameInfo,162			string? output)163		{164			if (string.IsNullOrEmpty(output))165				return;166			// The test output helper terminates everything with NewLine, but we really don't need that167			// extra blank line in our output.168			if (output.EndsWith(Environment.NewLine, StringComparison.Ordinal))169				output = output.Substring(0, output.Length - Environment.NewLine.Length);170			Logger.LogMessage(frameInfo, "      Output:");171			foreach (var line in output.Split(new[] { Environment.NewLine }, StringSplitOptions.None))172				Logger.LogImportantMessage(frameInfo, $"        {line}");173		}174		void RemoveExecutionOptions(string assemblyIdentifier)175		{176			using (ReaderWriterLockWrapper.WriteLock())177				executionOptionsByAssembly.Remove(assemblyIdentifier);178		}179		/// <summary>180		/// Called when <see cref="_ErrorMessage"/> is raised.181		/// </summary>182		/// <param name="args">An object that contains the event data.</param>183		protected virtual void HandleErrorMessage(MessageHandlerArgs<_ErrorMessage> args)184		{185			Guard.ArgumentNotNull(args);186			LogError("FATAL ERROR", args.Message);187		}188		/// <summary>189		/// Called when <see cref="TestAssemblyDiscoveryFinished"/> is raised.190		/// </summary>191		/// <param name="args">An object that contains the event data.</param>192		protected virtual void HandleTestAssemblyDiscoveryFinished(MessageHandlerArgs<TestAssemblyDiscoveryFinished> args)193		{194			Guard.ArgumentNotNull(args);195			var discoveryFinished = args.Message;196			var assemblyDisplayName = GetAssemblyDisplayName(discoveryFinished.Assembly);197			if (discoveryFinished.DiscoveryOptions.GetDiagnosticMessagesOrDefault())198			{199				var count =200					discoveryFinished.TestCasesToRun == discoveryFinished.TestCasesDiscovered201						? discoveryFinished.TestCasesDiscovered.ToString()202						: $"{discoveryFinished.TestCasesToRun} of {discoveryFinished.TestCasesDiscovered}";203				Logger.LogImportantMessage($"  Discovered:  {assemblyDisplayName} (found {count} test case{(discoveryFinished.TestCasesToRun == 1 ? "" : "s")})");204			}205			else206				Logger.LogImportantMessage($"  Discovered:  {assemblyDisplayName}");207		}208		/// <summary>209		/// Called when <see cref="TestAssemblyDiscoveryStarting"/> is raised.210		/// </summary>211		/// <param name="args">An object that contains the event data.</param>212		protected virtual void HandleTestAssemblyDiscoveryStarting(MessageHandlerArgs<TestAssemblyDiscoveryStarting> args)213		{214			Guard.ArgumentNotNull(args);215			var discoveryStarting = args.Message;216			var assemblyDisplayName = GetAssemblyDisplayName(discoveryStarting.Assembly);217			if (discoveryStarting.DiscoveryOptions.GetDiagnosticMessagesOrDefault())218			{219				var appDomainText = discoveryStarting.AppDomain switch220				{221					AppDomainOption.Enabled => $"app domain = on [{(discoveryStarting.ShadowCopy ? "shadow copy" : "no shadow copy")}], ",222					AppDomainOption.Disabled => $"app domain = off, ",223					_ => "",224				};225				Logger.LogImportantMessage($"  Discovering: {assemblyDisplayName} ({appDomainText}method display = {discoveryStarting.DiscoveryOptions.GetMethodDisplayOrDefault()}, method display options = {discoveryStarting.DiscoveryOptions.GetMethodDisplayOptionsOrDefault()})");226			}227			else228				Logger.LogImportantMessage($"  Discovering: {assemblyDisplayName}");229		}230		/// <summary>231		/// Called when <see cref="TestAssemblyExecutionFinished"/> is raised.232		/// </summary>233		/// <param name="args">An object that contains the event data.</param>234		protected virtual void HandleTestAssemblyExecutionFinished(MessageHandlerArgs<TestAssemblyExecutionFinished> args)235		{236			Guard.ArgumentNotNull(args);237			var executionFinished = args.Message;238			Logger.LogImportantMessage($"  Finished:    {GetAssemblyDisplayName(executionFinished.Assembly)}");239			RemoveExecutionOptions(executionFinished.Assembly.Identifier);240		}241		/// <summary>242		/// Called when <see cref="TestAssemblyExecutionStarting"/> is raised.243		/// </summary>244		/// <param name="args">An object that contains the event data.</param>245		protected virtual void HandleTestAssemblyExecutionStarting(MessageHandlerArgs<TestAssemblyExecutionStarting> args)246		{247			Guard.ArgumentNotNull(args);248			var executionStarting = args.Message;249			AddExecutionOptions(executionStarting.Assembly.Identifier, executionStarting.ExecutionOptions);250			var assemblyDisplayName = GetAssemblyDisplayName(executionStarting.Assembly);251			if (executionStarting.ExecutionOptions.GetDiagnosticMessagesOrDefault())252			{253				var threadCount = executionStarting.ExecutionOptions.GetMaxParallelThreadsOrDefault();254				var threadCountText = threadCount < 0 ? "unlimited" : threadCount.ToString();255				Logger.LogImportantMessage($"  Starting:    {assemblyDisplayName} (parallel test collections = {(!executionStarting.ExecutionOptions.GetDisableParallelizationOrDefault() ? "on" : "off")}, max threads = {threadCountText})");256			}257			else258				Logger.LogImportantMessage($"  Starting:    {assemblyDisplayName}");259		}260		/// <summary>261		/// Called when <see cref="_TestAssemblyCleanupFailure"/> is raised.262		/// </summary>263		/// <param name="args">An object that contains the event data.</param>264		protected virtual void HandleTestAssemblyCleanupFailure(MessageHandlerArgs<_TestAssemblyCleanupFailure> args)265		{266			Guard.ArgumentNotNull(args);267			var metadata = MetadataCache.TryGetAssemblyMetadata(args.Message);268			if (metadata != null)269				LogError($"Test Assembly Cleanup Failure ({metadata.AssemblyPath})", args.Message);270			else271				LogError($"Test Assembly Cleanup Failure (<unknown test assembly>)", args.Message);272		}273		/// <summary>274		/// Called when <see cref="_TestAssemblyFinished"/> is raised.275		/// </summary>276		/// <param name="args">An object that contains the event data.</param>277		protected virtual void HandleTestAssemblyFinished(MessageHandlerArgs<_TestAssemblyFinished> args)278		{279			Guard.ArgumentNotNull(args);280			// We don't remove this metadata from the cache, because the assembly ID is how we map281			// execution results. We need the cache to still contain that mapping so we can print282			// results at the end of execution.283		}284		/// <summary>285		/// Called when <see cref="_TestAssemblyStarting"/> is raised.286		/// </summary>287		/// <param name="args">An object that contains the event data.</param>288		protected virtual void HandleTestAssemblyStarting(MessageHandlerArgs<_TestAssemblyStarting> args)289		{290			Guard.ArgumentNotNull(args);291			MetadataCache.Set(args.Message);292		}293		/// <summary>294		/// Called when <see cref="_TestCaseCleanupFailure"/> is raised.295		/// </summary>296		/// <param name="args">An object that contains the event data.</param>297		protected virtual void HandleTestCaseCleanupFailure(MessageHandlerArgs<_TestCaseCleanupFailure> args)298		{299			Guard.ArgumentNotNull(args);300			var metadata = MetadataCache.TryGetTestCaseMetadata(args.Message);301			if (metadata != null)302				LogError($"Test Case Cleanup Failure ({metadata.TestCaseDisplayName})", args.Message);303			else304				LogError("Test Case Cleanup Failure (<unknown test case>)", args.Message);305		}306		/// <summary>307		/// Called when <see cref="_TestCaseFinished"/> is raised.308		/// </summary>309		/// <param name="args">An object that contains the event data.</param>310		protected virtual void HandleTestCaseFinished(MessageHandlerArgs<_TestCaseFinished> args)311		{312			Guard.ArgumentNotNull(args);313			MetadataCache.TryRemove(args.Message);314		}315		/// <summary>316		/// Called when <see cref="_TestCaseStarting"/> is raised.317		/// </summary>318		/// <param name="args">An object that contains the event data.</param>319		protected virtual void HandleTestCaseStarting(MessageHandlerArgs<_TestCaseStarting> args)320		{321			Guard.ArgumentNotNull(args);322			MetadataCache.Set(args.Message);323		}324		/// <summary>325		/// Called when <see cref="_TestClassCleanupFailure"/> is raised.326		/// </summary>327		/// <param name="args">An object that contains the event data.</param>328		protected virtual void HandleTestClassCleanupFailure(MessageHandlerArgs<_TestClassCleanupFailure> args)329		{330			Guard.ArgumentNotNull(args);331			var metadata = MetadataCache.TryGetClassMetadata(args.Message);332			if (metadata != null)333				LogError($"Test Class Cleanup Failure ({metadata.TestClass})", args.Message);334			else335				LogError("Test Class Cleanup Failure (<unknown test class>)", args.Message);336		}337		/// <summary>338		/// Called when <see cref="_TestClassFinished"/> is raised.339		/// </summary>340		/// <param name="args">An object that contains the event data.</param>341		protected virtual void HandleTestClassFinished(MessageHandlerArgs<_TestClassFinished> args)342		{343			Guard.ArgumentNotNull(args);344			MetadataCache.TryRemove(args.Message);345		}346		/// <summary>347		/// Called when <see cref="_TestClassStarting"/> is raised.348		/// </summary>349		/// <param name="args">An object that contains the event data.</param>350		protected virtual void HandleTestClassStarting(MessageHandlerArgs<_TestClassStarting> args)351		{352			Guard.ArgumentNotNull(args);353			MetadataCache.Set(args.Message);354		}355		/// <summary>356		/// Called when <see cref="_TestCleanupFailure"/> is raised.357		/// </summary>358		/// <param name="args">An object that contains the event data.</param>359		protected virtual void HandleTestCleanupFailure(MessageHandlerArgs<_TestCleanupFailure> args)360		{361			Guard.ArgumentNotNull(args);362			var metadata = MetadataCache.TryGetTestMetadata(args.Message);363			if (metadata != null)364				LogError($"Test Cleanup Failure ({metadata.TestDisplayName})", args.Message);365			else366				LogError("Test Cleanup Failure (<unknown test>)", args.Message);367		}368		/// <summary>369		/// Called when <see cref="_TestCollectionCleanupFailure"/> is raised.370		/// </summary>371		/// <param name="args">An object that contains the event data.</param>372		protected virtual void HandleTestCollectionCleanupFailure(MessageHandlerArgs<_TestCollectionCleanupFailure> args)373		{374			Guard.ArgumentNotNull(args);375			var metadata = MetadataCache.TryGetCollectionMetadata(args.Message);376			if (metadata != null)377				LogError($"Test Collection Cleanup Failure ({metadata.TestCollectionDisplayName})", args.Message);378			else379				LogError($"Test Collection Cleanup Failure (<unknown test collection>)", args.Message);380		}381		/// <summary>382		/// Called when <see cref="_TestCollectionFinished"/> is raised.383		/// </summary>384		/// <param name="args">An object that contains the event data.</param>385		protected virtual void HandleTestCollectionFinished(MessageHandlerArgs<_TestCollectionFinished> args)386		{387			Guard.ArgumentNotNull(args);388			MetadataCache.TryRemove(args.Message);389		}390		/// <summary>391		/// Called when <see cref="_TestCollectionStarting"/> is raised.392		/// </summary>393		/// <param name="args">An object that contains the event data.</param>394		protected virtual void HandleTestCollectionStarting(MessageHandlerArgs<_TestCollectionStarting> args)395		{396			Guard.ArgumentNotNull(args);397			MetadataCache.Set(args.Message);398		}399		/// <summary>400		/// Called when <see cref="TestExecutionSummaries"/> is raised.401		/// </summary>402		/// <param name="args">An object that contains the event data.</param>403		protected virtual void HandleTestExecutionSummaries(MessageHandlerArgs<TestExecutionSummaries> args)404		{405			Guard.ArgumentNotNull(args);406			WriteDefaultSummary(Logger, args.Message);407		}408		/// <summary>409		/// Called when <see cref="_TestFailed"/> is raised.410		/// </summary>411		/// <param name="args">An object that contains the event data.</param>412		protected virtual void HandleTestFailed(MessageHandlerArgs<_TestFailed> args)413		{414			Guard.ArgumentNotNull(args);415			var testFailed = args.Message;416			var frameInfo = StackFrameInfo.FromErrorMetadata(testFailed);417			var metadata = MetadataCache.TryGetTestMetadata(testFailed);418			lock (Logger.LockObject)419			{420				if (metadata != null)421					Logger.LogError(frameInfo, $"    {Escape(metadata.TestDisplayName)} [FAIL]");422				else423					Logger.LogError(frameInfo, "    <unknown test> [FAIL]");424				foreach (var messageLine in ExceptionUtility.CombineMessages(testFailed).Split(new[] { Environment.NewLine }, StringSplitOptions.None))425					Logger.LogImportantMessage(frameInfo, $"      {messageLine}");426				LogStackTrace(frameInfo, ExceptionUtility.CombineStackTraces(testFailed));427				LogOutput(frameInfo, testFailed.Output);428			}429		}430		/// <summary>431		/// Called when <see cref="_TestFinished"/> is raised.432		/// </summary>433		/// <param name="args">An object that contains the event data.</param>434		protected virtual void HandleTestFinished(MessageHandlerArgs<_TestFinished> args)435		{436			Guard.ArgumentNotNull(args);437			//MetadataCache.TryRemove(args.Message);438		}439		/// <summary>440		/// Called when <see cref="_TestMethodCleanupFailure"/> is raised.441		/// </summary>442		/// <param name="args">An object that contains the event data.</param>443		protected virtual void HandleTestMethodCleanupFailure(MessageHandlerArgs<_TestMethodCleanupFailure> args)444		{445			Guard.ArgumentNotNull(args);446			var cleanupFailure = args.Message;447			var metadata = MetadataCache.TryGetMethodMetadata(args.Message);448			if (metadata != null)449				LogError($"Test Method Cleanup Failure ({metadata.TestMethod})", cleanupFailure);450			else451				LogError("Test Method Cleanup Failure (<unknown test method>)", cleanupFailure);452		}453		/// <summary>454		/// Called when <see cref="_TestMethodFinished"/> is raised.455		/// </summary>456		/// <param name="args">An object that contains the event data.</param>457		protected virtual void HandleTestMethodFinished(MessageHandlerArgs<_TestMethodFinished> args)458		{459			Guard.ArgumentNotNull(args);460			MetadataCache.TryRemove(args.Message);461		}462		/// <summary>463		/// Called when <see cref="_TestMethodStarting"/> is raised.464		/// </summary>465		/// <param name="args">An object that contains the event data.</param>466		protected virtual void HandleTestMethodStarting(MessageHandlerArgs<_TestMethodStarting> args)467		{468			Guard.ArgumentNotNull(args);469			MetadataCache.Set(args.Message);470		}471		/// <summary>472		/// Called when <see cref="_TestPassed"/> is raised.473		/// </summary>474		/// <param name="args">An object that contains the event data.</param>475		protected virtual void HandleTestPassed(MessageHandlerArgs<_TestPassed> args)476		{477			Guard.ArgumentNotNull(args);478			var testPassed = args.Message;479			var assemblyMetadata = MetadataCache.TryGetAssemblyMetadata(testPassed);480			if (!string.IsNullOrEmpty(testPassed.Output) &&481				GetExecutionOptions(assemblyMetadata?.AssemblyPath).GetDiagnosticMessagesOrDefault())482			{483				lock (Logger.LockObject)484				{485					var testMetadata = MetadataCache.TryGetTestMetadata(testPassed);486					if (testMetadata != null)487						Logger.LogImportantMessage($"    {Escape(testMetadata.TestDisplayName)} [PASS]");488					else489						Logger.LogImportantMessage("    <unknown test> [PASS]");490					LogOutput(StackFrameInfo.None, testPassed.Output);491				}492			}493			// TODO: What to do if assembly metadata cannot be found?494		}495		/// <summary>496		/// Called when <see cref="_TestSkipped"/> is raised.497		/// </summary>498		/// <param name="args">An object that contains the event data.</param>499		protected virtual void HandleTestSkipped(MessageHandlerArgs<_TestSkipped> args)500		{501			Guard.ArgumentNotNull(args);502			lock (Logger.LockObject)503			{504				var testSkipped = args.Message;505				var testMetadata = MetadataCache.TryGetTestMetadata(testSkipped);506				if (testMetadata != null)507					Logger.LogWarning($"    {Escape(testMetadata.TestDisplayName)} [SKIP]");508				else509					Logger.LogWarning("    <unknown test> [SKIP]");510				Logger.LogImportantMessage($"      {EscapeMultiLineIndent(testSkipped.Reason, "      ")}");511			}512		}513		/// <summary>514		/// Called when <see cref="_TestStarting"/> is raised.515		/// </summary>516		/// <param name="args">An object that contains the event data.</param>517		protected virtual void HandleTestStarting(MessageHandlerArgs<_TestStarting> args)518		{519			Guard.ArgumentNotNull(args);520			MetadataCache.Set(args.Message);521		}522		/// <summary>523		/// Writes the default summary to the given logger. Can be used by other reporters who also wish to write the524		/// standard summary information.525		/// </summary>526		/// <param name="logger">The logger used to send result messages to.</param>527		/// <param name="summaries">The execution summary to display.</param>528		public void WriteDefaultSummary(IRunnerLogger logger, TestExecutionSummaries summaries)529		{530			Guard.ArgumentNotNull(logger);531			Guard.ArgumentNotNull(summaries);532			logger.LogImportantMessage("=== TEST EXECUTION SUMMARY ===");533			var summariesWithDisplayName =534				summaries535					.SummariesByAssemblyUniqueID536					.Select(537						summary => (538							summary.Summary,539							summary.AssemblyUniqueID,540							AssemblyDisplayName: MetadataCache.TryGetAssemblyMetadata(summary.AssemblyUniqueID)?.SimpleAssemblyName() ?? "<unknown assembly>"541						)542					).OrderBy(summary => summary.AssemblyDisplayName)543					.ToList();544			var totalTestsRun = summaries.SummariesByAssemblyUniqueID.Sum(summary => summary.Summary.Total);545			var totalTestsFailed = summaries.SummariesByAssemblyUniqueID.Sum(summary => summary.Summary.Failed);546			var totalTestsSkipped = summaries.SummariesByAssemblyUniqueID.Sum(summary => summary.Summary.Skipped);547			var totalTime = summaries.SummariesByAssemblyUniqueID.Sum(summary => summary.Summary.Time).ToString("0.000s");548			var totalErrors = summaries.SummariesByAssemblyUniqueID.Sum(summary => summary.Summary.Errors);549			var longestAssemblyName = summariesWithDisplayName.Max(summary => summary.AssemblyDisplayName.Length);550			var longestTotal = totalTestsRun.ToString().Length;551			var longestFailed = totalTestsFailed.ToString().Length;552			var longestSkipped = totalTestsSkipped.ToString().Length;553			var longestTime = totalTime.Length;554			var longestErrors = totalErrors.ToString().Length;555			foreach (var (summary, assemblyUniqueID, assemblyDisplayName) in summariesWithDisplayName)556			{557				if (summary.Total == 0)558					logger.LogImportantMessage($"   {assemblyDisplayName.PadRight(longestAssemblyName)}  Total: {"0".PadLeft(longestTotal)}");559				else560					logger.LogImportantMessage($"   {assemblyDisplayName.PadRight(longestAssemblyName)}  Total: {summary.Total.ToString().PadLeft(longestTotal)}, Errors: {summary.Errors.ToString().PadLeft(longestErrors)}, Failed: {summary.Failed.ToString().PadLeft(longestFailed)}, Skipped: {summary.Skipped.ToString().PadLeft(longestSkipped)}, Time: {summary.Time.ToString("0.000s").PadLeft(longestTime)}");561			}562			if (summaries.SummariesByAssemblyUniqueID.Count > 1)563			{564				logger.LogImportantMessage($"   {" ".PadRight(longestAssemblyName)}         {"-".PadRight(longestTotal, '-')}          {"-".PadRight(longestErrors, '-')}          {"-".PadRight(longestFailed, '-')}           {"-".PadRight(longestSkipped, '-')}        {"-".PadRight(longestTime, '-')}");565				logger.LogImportantMessage($"   {"GRAND TOTAL:".PadLeft(longestAssemblyName + 8)} {totalTestsRun}          {totalErrors}          {totalTestsFailed}           {totalTestsSkipped}        {totalTime} ({summaries.ElapsedClockTime.TotalSeconds:0.000s})");566			}567		}568		class ReaderWriterLockWrapper : IDisposable569		{570			static readonly ReaderWriterLockSlim @lock = new();571			static readonly ReaderWriterLockWrapper lockForRead = new(@lock.ExitReadLock);572			static readonly ReaderWriterLockWrapper lockForWrite = new(@lock.ExitWriteLock);573			readonly Action unlock;574			ReaderWriterLockWrapper(Action unlock)575			{576				this.unlock = unlock;577			}578			public void Dispose()579			{580				unlock();581			}582			public static IDisposable ReadLock()583			{584				@lock.EnterReadLock();585				return lockForRead;586			}587			public static IDisposable WriteLock()588			{589				@lock.EnterWriteLock();590				return lockForWrite;591			}592		}593	}594}...DefaultRunnerReporterWithTypesMessageHandler.cs
Source:DefaultRunnerReporterWithTypesMessageHandler.cs  
...50			string? assemblyFilename,51			ITestFrameworkExecutionOptions executionOptions)52		{53			Guard.NotNull("Attempted to log messages for an XunitProjectAssembly without first setting AssemblyFilename", assemblyFilename);54			using (ReaderWriterLockWrapper.WriteLock())55				executionOptionsByAssembly[assemblyFilename] = executionOptions;56		}57		/// <summary>58		/// Escapes text for display purposes.59		/// </summary>60		/// <param name="text">The text to be escaped</param>61		/// <returns>The escaped text</returns>62		protected virtual string Escape(string? text)63		{64			if (text == null)65				return string.Empty;66			return text.Replace("\r", "\\r").Replace("\n", "\\n").Replace("\t", "\\t").Replace("\0", "\\0");67		}68		/// <summary>69		/// Gets the display name of a test assembly from a test assembly message.70		/// </summary>71		/// <param name="assemblyMessage">The test assembly message</param>72		/// <returns>The assembly display name</returns>73		protected virtual string GetAssemblyDisplayName(ITestAssemblyMessage assemblyMessage)74		{75			Guard.ArgumentNotNull(nameof(assemblyMessage), assemblyMessage);76			return77				string.IsNullOrWhiteSpace(assemblyMessage.TestAssembly.Assembly.AssemblyPath)78					? "<dynamic>"79					: Path.GetFileNameWithoutExtension(assemblyMessage.TestAssembly.Assembly.AssemblyPath);80		}81		/// <summary>82		/// Gets the display name of a test assembly from a test assembly message.83		/// </summary>84		/// <param name="assembly">The test assembly</param>85		/// <returns>The assembly display name</returns>86		protected virtual string GetAssemblyDisplayName(XunitProjectAssembly assembly)87		{88			Guard.ArgumentNotNull(nameof(assembly), assembly);89			return assembly.AssemblyDisplayName;90		}91		/// <summary>92		/// Get the test framework options for the given assembly. If it cannot find them, then it93		/// returns a default set of options.94		/// </summary>95		/// <param name="assemblyFilename">The test assembly filename</param>96		protected ITestFrameworkExecutionOptions GetExecutionOptions(string assemblyFilename)97		{98			Guard.ArgumentNotNull(nameof(assemblyFilename), assemblyFilename);99			using (ReaderWriterLockWrapper.ReadLock())100				if (executionOptionsByAssembly.TryGetValue(assemblyFilename, out var result))101					return result;102			return defaultExecutionOptions;103		}104		/// <summary>105		/// Logs an error message to the logger.106		/// </summary>107		/// <param name="failureType">The type of the failure</param>108		/// <param name="failureInfo">The failure information</param>109		protected void LogError(110			string failureType,111			IFailureInformation failureInfo)112		{113			Guard.ArgumentNotNull(nameof(failureType), failureType);114			Guard.ArgumentNotNull(nameof(failureInfo), failureInfo);115			var frameInfo = StackFrameInfo.FromFailure(failureInfo);116			lock (Logger.LockObject)117			{118				Logger.LogError(frameInfo, $"    [{failureType}] {Escape(failureInfo.ExceptionTypes.FirstOrDefault() ?? "(Unknown Exception Type)")}");119				foreach (var messageLine in ExceptionUtility.CombineMessages(failureInfo).Split(new[] { Environment.NewLine }, StringSplitOptions.None))120					Logger.LogImportantMessage(frameInfo, $"      {messageLine}");121				LogStackTrace(frameInfo, ExceptionUtility.CombineStackTraces(failureInfo));122			}123		}124		/// <summary>125		/// Logs a stack trace to the logger.126		/// </summary>127		protected virtual void LogStackTrace(128			StackFrameInfo frameInfo,129			string? stackTrace)130		{131			if (string.IsNullOrEmpty(stackTrace))132				return;133			Logger.LogMessage(frameInfo, "      Stack Trace:");134			foreach (var stackFrame in stackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.None))135				Logger.LogImportantMessage(frameInfo, $"        {StackFrameTransformer.TransformFrame(stackFrame, defaultDirectory)}");136		}137		/// <summary>138		/// Lots test output to the logger.139		/// </summary>140		protected virtual void LogOutput(141			StackFrameInfo frameInfo,142			string? output)143		{144			if (string.IsNullOrEmpty(output))145				return;146			// ITestOutputHelper terminates everything with NewLine, but we really don't need that147			// extra blank line in our output.148			if (output.EndsWith(Environment.NewLine, StringComparison.Ordinal))149				output = output.Substring(0, output.Length - Environment.NewLine.Length);150			Logger.LogMessage(frameInfo, "      Output:");151			foreach (var line in output.Split(new[] { Environment.NewLine }, StringSplitOptions.None))152				Logger.LogImportantMessage(frameInfo, $"        {line}");153		}154		void RemoveExecutionOptions(string? assemblyFilename)155		{156			Guard.NotNull("Attempted to log messages for an XunitProjectAssembly without first setting AssemblyFilename", assemblyFilename);157			using (ReaderWriterLockWrapper.WriteLock())158				executionOptionsByAssembly.Remove(assemblyFilename);159		}160		/// <summary>161		/// Called when <see cref="IErrorMessage"/> is raised.162		/// </summary>163		/// <param name="args">An object that contains the event data.</param>164		protected virtual void HandleErrorMessage(MessageHandlerArgs<IErrorMessage> args)165		{166			Guard.ArgumentNotNull(nameof(args), args);167			LogError("FATAL ERROR", args.Message);168		}169		/// <summary>170		/// Called when <see cref="ITestAssemblyDiscoveryFinished"/> is raised.171		/// </summary>172		/// <param name="args">An object that contains the event data.</param>173		protected virtual void HandleTestAssemblyDiscoveryFinished(MessageHandlerArgs<ITestAssemblyDiscoveryFinished> args)174		{175			Guard.ArgumentNotNull(nameof(args), args);176			var discoveryFinished = args.Message;177			var assemblyDisplayName = GetAssemblyDisplayName(discoveryFinished.Assembly);178			if (discoveryFinished.DiscoveryOptions.GetDiagnosticMessagesOrDefault())179			{180				var count =181					discoveryFinished.TestCasesToRun == discoveryFinished.TestCasesDiscovered182						? discoveryFinished.TestCasesDiscovered.ToString()183						: $"{discoveryFinished.TestCasesToRun} of {discoveryFinished.TestCasesDiscovered}";184				Logger.LogImportantMessage($"  Discovered:  {assemblyDisplayName} (found {count} test case{(discoveryFinished.TestCasesToRun == 1 ? "" : "s")})");185			}186			else187				Logger.LogImportantMessage($"  Discovered:  {assemblyDisplayName}");188		}189		/// <summary>190		/// Called when <see cref="ITestAssemblyDiscoveryStarting"/> is raised.191		/// </summary>192		/// <param name="args">An object that contains the event data.</param>193		protected virtual void HandleTestAssemblyDiscoveryStarting(MessageHandlerArgs<ITestAssemblyDiscoveryStarting> args)194		{195			Guard.ArgumentNotNull(nameof(args), args);196			var discoveryStarting = args.Message;197			var assemblyDisplayName = GetAssemblyDisplayName(discoveryStarting.Assembly);198			if (discoveryStarting.DiscoveryOptions.GetDiagnosticMessagesOrDefault())199			{200				var appDomainText = discoveryStarting.AppDomain switch201				{202					AppDomainOption.Enabled => $"app domain = on [{(discoveryStarting.ShadowCopy ? "shadow copy" : "no shadow copy")}], ",203					AppDomainOption.Disabled => $"app domain = off, ",204					_ => "",205				};206				Logger.LogImportantMessage($"  Discovering: {assemblyDisplayName} ({appDomainText}method display = {discoveryStarting.DiscoveryOptions.GetMethodDisplayOrDefault()}, method display options = {discoveryStarting.DiscoveryOptions.GetMethodDisplayOptionsOrDefault()})");207			}208			else209				Logger.LogImportantMessage($"  Discovering: {assemblyDisplayName}");210		}211		/// <summary>212		/// Called when <see cref="ITestAssemblyExecutionFinished"/> is raised.213		/// </summary>214		/// <param name="args">An object that contains the event data.</param>215		protected virtual void HandleTestAssemblyExecutionFinished(MessageHandlerArgs<ITestAssemblyExecutionFinished> args)216		{217			Guard.ArgumentNotNull(nameof(args), args);218			var executionFinished = args.Message;219			Logger.LogImportantMessage($"  Finished:    {GetAssemblyDisplayName(executionFinished.Assembly)}");220			RemoveExecutionOptions(executionFinished.Assembly.AssemblyFilename);221		}222		/// <summary>223		/// Called when <see cref="ITestAssemblyExecutionStarting"/> is raised.224		/// </summary>225		/// <param name="args">An object that contains the event data.</param>226		protected virtual void HandleTestAssemblyExecutionStarting(MessageHandlerArgs<ITestAssemblyExecutionStarting> args)227		{228			Guard.ArgumentNotNull(nameof(args), args);229			var executionStarting = args.Message;230			AddExecutionOptions(executionStarting.Assembly.AssemblyFilename, executionStarting.ExecutionOptions);231			var assemblyDisplayName = GetAssemblyDisplayName(executionStarting.Assembly);232			if (executionStarting.ExecutionOptions.GetDiagnosticMessagesOrDefault())233			{234				var threadCount = executionStarting.ExecutionOptions.GetMaxParallelThreadsOrDefault();235				var threadCountText = threadCount < 0 ? "unlimited" : threadCount.ToString();236				Logger.LogImportantMessage($"  Starting:    {assemblyDisplayName} (parallel test collections = {(!executionStarting.ExecutionOptions.GetDisableParallelizationOrDefault() ? "on" : "off")}, max threads = {threadCountText})");237			}238			else239				Logger.LogImportantMessage($"  Starting:    {assemblyDisplayName}");240		}241		/// <summary>242		/// Called when <see cref="ITestAssemblyCleanupFailure"/> is raised.243		/// </summary>244		/// <param name="args">An object that contains the event data.</param>245		protected virtual void HandleTestAssemblyCleanupFailure(MessageHandlerArgs<ITestAssemblyCleanupFailure> args)246		{247			Guard.ArgumentNotNull(nameof(args), args);248			LogError($"Test Assembly Cleanup Failure ({args.Message.TestAssembly.Assembly.AssemblyPath})", args.Message);249		}250		/// <summary>251		/// Called when <see cref="ITestCaseCleanupFailure"/> is raised.252		/// </summary>253		/// <param name="args">An object that contains the event data.</param>254		protected virtual void HandleTestCaseCleanupFailure(MessageHandlerArgs<ITestCaseCleanupFailure> args)255		{256			Guard.ArgumentNotNull(nameof(args), args);257			LogError($"Test Case Cleanup Failure ({args.Message.TestCase.DisplayName})", args.Message);258		}259		/// <summary>260		/// Called when <see cref="ITestClassCleanupFailure"/> is raised.261		/// </summary>262		/// <param name="args">An object that contains the event data.</param>263		protected virtual void HandleTestClassCleanupFailure(MessageHandlerArgs<ITestClassCleanupFailure> args)264		{265			Guard.ArgumentNotNull(nameof(args), args);266			LogError($"Test Class Cleanup Failure ({args.Message.TestClass.Class.Name})", args.Message);267		}268		/// <summary>269		/// Called when <see cref="ITestCleanupFailure"/> is raised.270		/// </summary>271		/// <param name="args">An object that contains the event data.</param>272		protected virtual void HandleTestCleanupFailure(MessageHandlerArgs<ITestCleanupFailure> args)273		{274			Guard.ArgumentNotNull(nameof(args), args);275			LogError($"Test Cleanup Failure ({args.Message.Test.DisplayName})", args.Message);276		}277		/// <summary>278		/// Called when <see cref="ITestCollectionCleanupFailure"/> is raised.279		/// </summary>280		/// <param name="args">An object that contains the event data.</param>281		protected virtual void HandleTestCollectionCleanupFailure(MessageHandlerArgs<ITestCollectionCleanupFailure> args)282		{283			Guard.ArgumentNotNull(nameof(args), args);284			LogError($"Test Collection Cleanup Failure ({args.Message.TestCollection.DisplayName})", args.Message);285		}286		/// <summary>287		/// Called when <see cref="ITestExecutionSummary"/> is raised.288		/// </summary>289		/// <param name="args">An object that contains the event data.</param>290		protected virtual void HandleTestExecutionSummary(MessageHandlerArgs<ITestExecutionSummary> args)291		{292			Guard.ArgumentNotNull(nameof(args), args);293			WriteDefaultSummary(Logger, args.Message);294		}295		/// <summary>296		/// Called when <see cref="ITestFailed"/> is raised.297		/// </summary>298		/// <param name="args">An object that contains the event data.</param>299		protected virtual void HandleTestFailed(MessageHandlerArgs<ITestFailed> args)300		{301			Guard.ArgumentNotNull(nameof(args), args);302			var testFailed = args.Message;303			var frameInfo = StackFrameInfo.FromFailure(testFailed);304			lock (Logger.LockObject)305			{306				Logger.LogError(frameInfo, $"    {Escape(testFailed.Test.DisplayName)} [FAIL]");307				foreach (var messageLine in ExceptionUtility.CombineMessages(testFailed).Split(new[] { Environment.NewLine }, StringSplitOptions.None))308					Logger.LogImportantMessage(frameInfo, $"      {messageLine}");309				LogStackTrace(frameInfo, ExceptionUtility.CombineStackTraces(testFailed));310				LogOutput(frameInfo, testFailed.Output);311			}312		}313		/// <summary>314		/// Called when <see cref="ITestMethodCleanupFailure"/> is raised.315		/// </summary>316		/// <param name="args">An object that contains the event data.</param>317		protected virtual void HandleTestMethodCleanupFailure(MessageHandlerArgs<ITestMethodCleanupFailure> args)318		{319			Guard.ArgumentNotNull(nameof(args), args);320			LogError($"Test Method Cleanup Failure ({args.Message.TestMethod.Method.Name})", args.Message);321		}322		/// <summary>323		/// Called when <see cref="ITestPassed"/> is raised.324		/// </summary>325		/// <param name="args">An object that contains the event data.</param>326		protected virtual void HandleTestPassed(MessageHandlerArgs<ITestPassed> args)327		{328			Guard.ArgumentNotNull(nameof(args), args);329			var testPassed = args.Message;330			if (!string.IsNullOrEmpty(testPassed.Output) &&331				GetExecutionOptions(testPassed.TestAssembly.Assembly.AssemblyPath).GetDiagnosticMessagesOrDefault())332			{333				lock (Logger.LockObject)334				{335					Logger.LogImportantMessage($"    {Escape(testPassed.Test.DisplayName)} [PASS]");336					LogOutput(StackFrameInfo.None, testPassed.Output);337				}338			}339		}340		/// <summary>341		/// Called when <see cref="ITestSkipped"/> is raised.342		/// </summary>343		/// <param name="args">An object that contains the event data.</param>344		protected virtual void HandleTestSkipped(MessageHandlerArgs<ITestSkipped> args)345		{346			Guard.ArgumentNotNull(nameof(args), args);347			lock (Logger.LockObject)348			{349				var testSkipped = args.Message;350				Logger.LogWarning($"    {Escape(testSkipped.Test.DisplayName)} [SKIP]");351				Logger.LogImportantMessage($"      {Escape(testSkipped.Reason)}");352			}353		}354		/// <summary>355		/// Writes the default summary to the given logger. Can be used by other reporters who also wish to write the356		/// standard summary information.357		/// </summary>358		/// <param name="logger">The logger used to send result messages to.</param>359		/// <param name="executionSummary">The execution summary to display.</param>360		public static void WriteDefaultSummary(IRunnerLogger logger, ITestExecutionSummary executionSummary)361		{362			Guard.ArgumentNotNull(nameof(logger), logger);363			Guard.ArgumentNotNull(nameof(executionSummary), executionSummary);364			logger.LogImportantMessage("=== TEST EXECUTION SUMMARY ===");365			var totalTestsRun = executionSummary.Summaries.Sum(summary => summary.Value.Total);366			var totalTestsFailed = executionSummary.Summaries.Sum(summary => summary.Value.Failed);367			var totalTestsSkipped = executionSummary.Summaries.Sum(summary => summary.Value.Skipped);368			var totalTime = executionSummary.Summaries.Sum(summary => summary.Value.Time).ToString("0.000s");369			var totalErrors = executionSummary.Summaries.Sum(summary => summary.Value.Errors);370			var longestAssemblyName = executionSummary.Summaries.Max(summary => summary.Key.Length);371			var longestTotal = totalTestsRun.ToString().Length;372			var longestFailed = totalTestsFailed.ToString().Length;373			var longestSkipped = totalTestsSkipped.ToString().Length;374			var longestTime = totalTime.Length;375			var longestErrors = totalErrors.ToString().Length;376			foreach (var summary in executionSummary.Summaries)377			{378				if (summary.Value.Total == 0)379					logger.LogImportantMessage($"   {summary.Key.PadRight(longestAssemblyName)}  Total: {"0".PadLeft(longestTotal)}");380				else381					logger.LogImportantMessage($"   {summary.Key.PadRight(longestAssemblyName)}  Total: {summary.Value.Total.ToString().PadLeft(longestTotal)}, Errors: {summary.Value.Errors.ToString().PadLeft(longestErrors)}, Failed: {summary.Value.Failed.ToString().PadLeft(longestFailed)}, Skipped: {summary.Value.Skipped.ToString().PadLeft(longestSkipped)}, Time: {summary.Value.Time.ToString("0.000s").PadLeft(longestTime)}");382			}383			if (executionSummary.Summaries.Count > 1)384			{385				logger.LogImportantMessage($"   {" ".PadRight(longestAssemblyName)}         {"-".PadRight(longestTotal, '-')}          {"-".PadRight(longestErrors, '-')}          {"-".PadRight(longestFailed, '-')}           {"-".PadRight(longestSkipped, '-')}        {"-".PadRight(longestTime, '-')}");386				logger.LogImportantMessage($"   {"GRAND TOTAL:".PadLeft(longestAssemblyName + 8)} {totalTestsRun}          {totalErrors}          {totalTestsFailed}           {totalTestsSkipped}        {totalTime} ({executionSummary.ElapsedClockTime.TotalSeconds.ToString("0.000s")})");387			}388		}389		class ReaderWriterLockWrapper : IDisposable390		{391			static readonly ReaderWriterLockSlim @lock = new ReaderWriterLockSlim();392			static readonly ReaderWriterLockWrapper lockForRead = new ReaderWriterLockWrapper(@lock.ExitReadLock);393			static readonly ReaderWriterLockWrapper lockForWrite = new ReaderWriterLockWrapper(@lock.ExitWriteLock);394			readonly Action unlock;395			ReaderWriterLockWrapper(Action unlock)396			{397				this.unlock = unlock;398			}399			public void Dispose()400			{401				unlock();402			}403			public static IDisposable ReadLock()404			{405				@lock.EnterReadLock();406				return lockForRead;407			}408			public static IDisposable WriteLock()409			{410				@lock.EnterWriteLock();411				return lockForWrite;412			}413		}414	}415}...WriteLock
Using AI Code Generation
1using Xunit.Runner.Common;2{3    {4        static void Main(string[] args)5        {6            ReaderWriterLockWrapper rw = new ReaderWriterLockWrapper();7            rw.WriteLock();8        }9    }10}WriteLock
Using AI Code Generation
1using Xunit.Runner.Common;2{3    {4        static void Main(string[] args)5        {6            var rwLock = new ReaderWriterLockWrapper();7            rwLock.WriteLock();8            rwLock.WriteUnlock();9        }10    }11}12using Xunit.Runner.Common;13{14    {15        static void Main(string[] args)16        {17            var rwLock = new ReaderWriterLockWrapper();18            rwLock.WriteLock();19            rwLock.WriteUnlock();20        }21    }22}WriteLock
Using AI Code Generation
1using Xunit.Runner.Common;2using Xunit.Runner.Common.IO;3{4    {5        public static void Main(string[] args)6        {7            var readerWriterLockWrapper = new ReaderWriterLockWrapper();8            readerWriterLockWrapper.WriteLock(() => { });9        }10    }11}12using Xunit.Runner.Common;13using Xunit.Runner.Common.IO;14{15    {16        public static void Main(string[] args)17        {18            var readerWriterLockWrapper = new ReaderWriterLockWrapper();19            readerWriterLockWrapper.WriteLock(() => { });20        }21    }22}23using Xunit.Runner.Common;24using Xunit.Runner.Common.IO;25{26    {27        public static void Main(string[] args)28        {29            var readerWriterLockWrapper = new ReaderWriterLockWrapper();30            readerWriterLockWrapper.WriteLock(() => { });31        }32    }33}34using Xunit.Runner.Common;35using Xunit.Runner.Common.IO;36{37    {38        public static void Main(string[] args)39        {40            var readerWriterLockWrapper = new ReaderWriterLockWrapper();41            readerWriterLockWrapper.WriteLock(() => { });42        }43    }44}45using Xunit.Runner.Common;46using Xunit.Runner.Common.IO;47{48    {49        public static void Main(string[] args)50        {51            var readerWriterLockWrapper = new ReaderWriterLockWrapper();52            readerWriterLockWrapper.WriteLock(() => { });53        }54    }55}56using Xunit.Runner.Common;57using Xunit.Runner.Common.IO;58{59    {60        public static void Main(string[] args)61        {62            var readerWriterLockWrapper = new ReaderWriterLockWrapper();WriteLock
Using AI Code Generation
1using System;2using System.Collections.Generic;3using System.Text;4using Xunit.Runner.Common;5{6    {7        static void Main(string[] args)8        {9            ReaderWriterLockWrapper rw = new ReaderWriterLockWrapper();10            rw.WriteLock();11        }12    }13}14using Xunit.Runner.Common;15{16    {17        static void Main(string[] args)18        {19            ReaderWriterLockWrapper rw = new ReaderWriterLockWrapper();20            rw.WriteLock();21        }22    }23}24using Xunit.Runner.Common;25{26    {27        static void Main(string[] args)28        {29            ReaderWriterLockWrapper rw = new ReaderWriterLockWrapper();30            rw.WriteLock();31        }32    }33}34using Xunit.Runner.Common;35{36    {37        static void Main(string[] args)38        {39            ReaderWriterLockWrapper rw = new ReaderWriterLockWrapper();40            rw.WriteLock();41        }42    }43}44using Xunit.Runner.Common;45{46    {47        static void Main(string[] args)48        {49            ReaderWriterLockWrapper rw = new ReaderWriterLockWrapper();50            rw.WriteLock();51        }52    }53}54using Xunit.Runner.Common;55{56    {57        static void Main(string[] args)58        {59            ReaderWriterLockWrapper rw = new ReaderWriterLockWrapper();60            rw.WriteLock();61        }62    }63}WriteLock
Using AI Code Generation
1using Xunit.Runner.Common;2using Xunit.Runner.Common.TestExecution;3using Xunit.Runner.Common.TestExecution.Messages;4{5    {6        public static void Main()7        {8            var readerWriterLock = new ReaderWriterLockWrapper();9            var testRunner = new TestRunner(readerWriterLock);10            testRunner.Run();11        }12        private readonly ReaderWriterLockWrapper _readerWriterLock;13        public TestRunner(ReaderWriterLockWrapper readerWriterLock)14        {15            _readerWriterLock = readerWriterLock;16        }17        public void Run()18        {19            _readerWriterLock.WriteLock(() =>20            {21            });22        }23    }24}25using Xunit.Runner.Common;26using Xunit.Runner.Common.TestExecution;27using Xunit.Runner.Common.TestExecution.Messages;28{29    {30        public static void Main()31        {32            var readerWriterLock = new ReaderWriterLockWrapper();33            var testRunner = new TestRunner(readerWriterLock);34            testRunner.Run();35        }36        private readonly ReaderWriterLockWrapper _readerWriterLock;37        public TestRunner(ReaderWriterLockWrapper readerWriterLock)38        {39            _readerWriterLock = readerWriterLock;40        }41        public void Run()42        {43            _readerWriterLock.WriteLock(() =>44            {45            });46        }47    }48}49using Xunit.Runner.Common;50using Xunit.Runner.Common.TestExecution;51using Xunit.Runner.Common.TestExecution.Messages;52{53    {54        public static void Main()55        {56            var readerWriterLock = new ReaderWriterLockWrapper();57            var testRunner = new TestRunner(readerWriterLock);58            testRunner.Run();59        }60        private readonly ReaderWriterLockWrapper _readerWriterLock;61        public TestRunner(ReaderWriterLockWrapper readerWriterLock)62        {63            _readerWriterLock = readerWriterLock;64        }65        public void Run()66        {67            _readerWriterLock.WriteLock(() =>68            {69            });70        }WriteLock
Using AI Code Generation
1using System;2using System.Threading;3using Xunit.Runner.Common;4{5    {6        static void Main(string[] args)7        {8            var rwLock = new ReaderWriterLockWrapper();9            var thread1 = new Thread(() => Read(rwLock));10            var thread2 = new Thread(() => Read(rwLock));11            var thread3 = new Thread(() => Write(rwLock));12            thread1.Start();13            thread2.Start();14            thread3.Start();15            thread1.Join();16            thread2.Join();17            thread3.Join();18        }19        static void Read(ReaderWriterLockWrapper rwLock)20        {21            using (rwLock.ReadLock())22            {23                Console.WriteLine("Read lock acquired");24            }25        }26        static void Write(ReaderWriterLockWrapper rwLock)27        {28            using (rwLock.WriteLock())29            {30                Console.WriteLine("Write lock acquired");31            }32        }33    }34}35using System;36using System.Threading;37using Xunit.Runner.Common;38{39    {40        static void Main(string[] args)41        {42            var rwLock = new ReaderWriterLockWrapper();43            var thread1 = new Thread(() => Read(rwLock));44            var thread2 = new Thread(() => Read(rwLock));45            var thread3 = new Thread(() => Write(rwLock));46            thread1.Start();47            thread2.Start();48            thread3.Start();49            thread1.Join();50            thread2.Join();51            thread3.Join();52        }53        static void Read(ReaderWriterLockWrapper rwLock)54        {55            using (rwLock.ReadLock())56            {57                Console.WriteLine("Read lock acquired");58            }59        }60        static void Write(ReaderWriterLockWrapper rwLock)61        {62            using (rwLock.WriteLock())63            {64                Console.WriteLine("Write lock acquired");65            }66        }67    }68}WriteLock
Using AI Code Generation
1using System;2using Xunit.Runner.Common;3{4    {5        public static void Main()6        {7            ReaderWriterLockWrapper rwlock = new ReaderWriterLockWrapper();8            rwlock.AcquireReadLock();9            rwlock.WriteLock();10            rwlock.ReleaseLock();11        }12    }13}14    0 Warning(s)15    0 Error(s)16using System;17using Xunit.Runner.Common;18{19    {20        public static void Main()21        {22            ReaderWriterLockWrapper rwlock = new ReaderWriterLockWrapper();23            rwlock.WriteLock();24            rwlock.WriteLock();25            rwlock.ReleaseLock();26        }27    }28}29    0 Warning(s)30    0 Error(s)31using System;32using Xunit.Runner.Common;33{34    {35        public static void Main()36        {37            ReaderWriterLockWrapper rwlock = new ReaderWriterLockWrapper();38            rwlock.WriteLock();39            rwlock.WriteLock();40            rwlock.ReleaseLock();41        }42    }43}44    0 Warning(s)45    0 Error(s)Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
