using System.Collections.Concurrent; using Microsoft.Extensions.Logging; using Moq; namespace UnitTests.ConsoleDrivers.V2; public class MainLoopCoordinatorTests { [Fact] public void TestMainLoopCoordinator_InputCrashes_ExceptionSurfacesMainThread () { var mockLogger = new Mock (); var beforeLogger = Logging.Logger; Logging.Logger = mockLogger.Object; var c = new MainLoopCoordinator (new TimedEvents (), // Runs on a separate thread (input thread) () => throw new Exception ("Crash on boot"), // Rest runs on main thread new ConcurrentQueue (), Mock.Of (), ()=>Mock.Of(), Mock.Of>()); // StartAsync boots the main loop and the input thread. But if the input class bombs // on startup it is important that the exception surface at the call site and not lost var ex = Assert.ThrowsAsync(c.StartAsync).Result; Assert.Equal ("Crash on boot", ex.InnerExceptions [0].Message); // Restore the original null logger to be polite to other tests Logging.Logger = beforeLogger; // Logs should explicitly call out that input loop crashed. mockLogger.Verify ( l => l.Log (LogLevel.Critical, It.IsAny (), It.Is ((v, t) => v.ToString () == "Input loop crashed"), It.IsAny (), It.IsAny> ()) , Times.Once); } /* [Fact] public void TestMainLoopCoordinator_InputExitsImmediately_ExceptionRaisedInMainThread () { // Runs on a separate thread (input thread) // But because it's just a mock it immediately exists var mockInputFactoryMethod = () => Mock.Of> (); var mockOutput = Mock.Of (); var mockInputProcessor = Mock.Of (); var inputQueue = new ConcurrentQueue (); var timedEvents = new TimedEvents (); var mainLoop = new MainLoop (); mainLoop.Initialize (timedEvents, inputQueue, mockInputProcessor, mockOutput ); var c = new MainLoopCoordinator (timedEvents, mockInputFactoryMethod, inputQueue, mockInputProcessor, ()=>mockOutput, mainLoop ); // TODO: This test has race condition // // * When the input loop exits it can happen // * - During boot // * - After boot // * // * If it happens in boot you get input exited // * If it happens after you get "Input loop exited early (stop not called)" // // Because the console input class does not block - i.e. breaks contract // We need to let the user know input has silently exited and all has gone bad. var ex = Assert.ThrowsAsync (c.StartAsync).Result; Assert.Equal ("Input loop exited during startup instead of entering read loop properly (i.e. and blocking)", ex.Message); }*/ }