/// <summary> /// Print program usage information /// </summary> /// static void Usage() { EventHandlerPipeline.Raise(new ProgramUsageEvent() { Lines = ArgumentParser.GetUsage() }); }
/// <summary> /// 4. Parse arguments and take action /// </summary> /// static int Main4(string[] args) { ArgumentParser.Parse(args); switch (ArgumentParser.OutputFormat) { case OutputFormats.Human: EventHandlerPipeline.Append(new HumanOutputEventHandler()); break; case OutputFormats.Machine: EventHandlerPipeline.Append(new MachineOutputEventHandler()); break; default: throw new Exception($"Unrecognised <outputformat> from parser {ArgumentParser.OutputFormat}"); } if (!ArgumentParser.Success) { throw ArgumentParseError(); } if (ArgumentParser.Help) { return(Help()); } if (ArgumentParser.InProc) { return(InProc(ArgumentParser.TestFiles[0])); } return(Main5(ArgumentParser.TestFiles)); }
/// <summary> /// Reinvoke testrunner to run an individual test file in its own process /// </summary> /// static bool Reinvoke(string testFile) { var exitCode = ProcessExtensions.ExecuteDotnet( ProgramPath, $"--inproc --outputformat machine \"{testFile}\"", (proc, line) => { var e = MachineReadableEventSerializer.TryDeserialize(line); EventHandlerPipeline.Raise( e ?? new StandardOutputEvent() { ProcessId = proc.Id, Message = line, }); }, (proc, line) => { EventHandlerPipeline.Raise( new ErrorOutputEvent() { ProcessId = proc.Id, Message = line, }); }); return(exitCode == 0); }
/// <summary> /// Handle user-facing error /// </summary> /// static void HandleUserException(UserException ue) { EventHandlerPipeline.Raise(new ProgramUserErrorEvent() { Message = ue.Message }); }
/// <summary> /// 2. Set up required event handlers /// </summary> /// static int Main2(string[] args) { EventHandlerPipeline.Append(new MethodResultEventHandler()); EventHandlerPipeline.Append(new TestResultEventHandler()); EventHandlerPipeline.Append(new TestClassResultEventHandler()); EventHandlerPipeline.Append(new TestAssemblyResultEventHandler()); EventHandlerPipeline.Append(new TestContextEventHandler()); return(Main3(args)); }
/// <summary> /// Run tests in a [TestClass] /// </summary> /// static public void Run(TestClass testClass) { Guard.NotNull(testClass, nameof(testClass)); EventHandlerPipeline.Raise(new TestClassBeginEvent() { FullName = testClass.FullName }); do { // // Handle exclusion from the command line // if (!ArgumentParser.ClassShouldRun(testClass.FullName)) { EventHandlerPipeline.Raise(new TestClassIgnoredEvent() { IgnoredFromCommandLine = true }); break; } // // Handle [Ignored] [TestClass] // if (testClass.IsIgnored) { EventHandlerPipeline.Raise(new TestClassIgnoredEvent()); break; } // // Run [ClassInitialize] method // if (!MethodRunner.RunClassInitializeMethod(testClass)) { break; } // // Run [TestMethod]s // foreach (var testMethod in testClass.TestMethods) { TestMethodRunner.Run(testMethod); } // // Run [ClassCleanup] method // MethodRunner.RunClassCleanupMethod(testClass); }while (false); EventHandlerPipeline.Raise(new TestClassEndEvent()); }
/// <summary> /// --inproc: Run an individual test file in-process /// </summary> /// static int InProc(string testFile) { var eventHandler = new ResultAccumulatingEventHandler(); using (EventHandlerPipeline.Append(eventHandler)) { TestAssemblyRunner.Run(testFile); } return(eventHandler.TestAssemblyResults.Last().Success ? 0 : 1); }
/// <summary> /// Switch to using a specified assembly .config file (if present) /// </summary> /// static public void SwitchTo(string configPath) { if (!File.Exists(configPath)) { return; } #if NET461 AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", configPath); // // The following hackery forces the new config file to take effect // // See http://stackoverflow.com/questions/6150644/change-default-app-config-at-runtime/6151688#6151688 // var initStateField = typeof(ConfigurationManager).GetField("s_initState", BindingFlags.NonPublic | BindingFlags.Static); if (initStateField != null) { initStateField.SetValue(null, 0); } var configSystemField = typeof(ConfigurationManager).GetField("s_configSystem", BindingFlags.NonPublic | BindingFlags.Static); if (configSystemField != null) { configSystemField.SetValue(null, null); } var clientConfigPathsType = typeof(ConfigurationManager) .Assembly .GetTypes() .FirstOrDefault(x => x.FullName == "System.Configuration.ClientConfigPaths"); var currentField = clientConfigPathsType != null ? clientConfigPathsType.GetField("s_current", BindingFlags.NonPublic | BindingFlags.Static) : null; if (currentField != null) { currentField.SetValue(null, null); } EventHandlerPipeline.Raise(new TestAssemblyConfigFileSwitchedEvent() { Path = configPath }); #endif }
/// <summary> /// Run a test method (plus its intialize and cleanup methods, if present) /// </summary> /// /// <remarks> /// If the test method is decorated with [Ignore], nothing is run /// </remarks> /// static public void Run(TestMethod testMethod) { EventHandlerPipeline.Raise(new TestBeginEvent() { Name = testMethod.Name }); do { // // Handle [Ignored] [TestMethod] // if (testMethod.IsIgnored) { EventHandlerPipeline.Raise(new TestIgnoredEvent()); break; } // // Create instance of [TestClass] // var instance = Activator.CreateInstance(testMethod.TestClass.Type); // // Set TestContext property (if present) // MethodRunner.RunTestContextSetter(testMethod.TestClass, instance); // // Run [TestInitialize] method // if (!MethodRunner.RunTestInitializeMethod(testMethod.TestClass, instance)) { break; } // // Run [TestMethod] // MethodRunner.RunTestMethod(testMethod, instance); // // Run [TestCleanup] method // MethodRunner.RunTestCleanupMethod(testMethod.TestClass, instance); }while (false); EventHandlerPipeline.Raise(new TestEndEvent()); }
/// <summary> /// Print program name, version, and copyright banner /// </summary> /// static void Banner() { var name = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).ProductName; var version = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).ProductVersion; var copyright = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).LegalCopyright; EventHandlerPipeline.Raise( new ProgramBannerEvent() { Lines = new[] { $"{name} v{version}", copyright, }, }); }
static public void RunTestContextSetter(TestClass testClass, object instance) { Guard.NotNull(testClass, nameof(testClass)); Guard.NotNull(instance, nameof(instance)); var method = testClass.TestContextSetter; if (method == null) { return; } EventHandlerPipeline.Raise(new TestContextSetterBeginEvent() { MethodName = method.Name }); var success = Run(method, instance, true, null, false); EventHandlerPipeline.Raise(new TestContextSetterEndEvent()); }
static public bool RunClassCleanupMethod(TestClass testClass) { Guard.NotNull(testClass, nameof(testClass)); var method = testClass.ClassCleanupMethod; if (method == null) { return(true); } EventHandlerPipeline.Raise(new ClassCleanupMethodBeginEvent() { MethodName = method.Name }); var success = Run(method, null, false, null, false); EventHandlerPipeline.Raise(new ClassCleanupMethodEndEvent()); return(success); }
static public bool RunTestMethod(TestMethod testMethod, object instance) { Guard.NotNull(testMethod, nameof(testMethod)); Guard.NotNull(instance, nameof(instance)); EventHandlerPipeline.Raise(new TestMethodBeginEvent() { MethodName = testMethod.Name }); var success = Run( testMethod.MethodInfo, instance, false, testMethod.ExpectedException, testMethod.AllowDerivedExpectedExceptionTypes); EventHandlerPipeline.Raise(new TestMethodEndEvent()); return(success); }
/// <summary> /// Reinvoke testrunner to run an individual test file in its own process /// </summary> /// static bool Reinvoke(string testFile) { var args = new List <string>(); args.Add("--inproc"); args.Add("--outputformat machine"); foreach (var @class in ArgumentParser.Classes) { args.Add($"--class {@class}"); } foreach (var method in ArgumentParser.Methods) { args.Add($"--method {method}"); } args.Add($"\"{testFile}\""); var exitCode = ProcessExtensions.ExecuteDotnet( Assembly.GetExecutingAssembly().Location, string.Join(" ", args), (proc, line) => { var e = MachineReadableEventSerializer.TryDeserialize(line); EventHandlerPipeline.Raise( e ?? new StandardOutputEvent() { ProcessId = proc.Id, Message = line, }); }, (proc, line) => { EventHandlerPipeline.Raise( new ErrorOutputEvent() { ProcessId = proc.Id, Message = line, }); }); return(exitCode == 0); }
static public bool RunTestInitializeMethod(TestClass testClass, object instance) { Guard.NotNull(testClass, nameof(testClass)); Guard.NotNull(instance, nameof(instance)); var method = testClass.TestInitializeMethod; if (method == null) { return(true); } EventHandlerPipeline.Raise(new TestInitializeMethodBeginEvent() { MethodName = method.Name }); var success = Run(method, instance, false, null, false); EventHandlerPipeline.Raise(new TestInitializeMethodEndEvent()); return(success); }
static public bool RunClassInitializeMethod(TestClass testClass) { Guard.NotNull(testClass, nameof(testClass)); var method = testClass.ClassInitializeMethod; if (method == null) { return(true); } EventHandlerPipeline.Raise( new ClassInitializeMethodBeginEvent() { MethodName = method.Name, FirstTestMethodName = testClass.TestMethods.First().Name, }); var success = Run(method, null, true, null, false); EventHandlerPipeline.Raise(new ClassInitializeMethodEndEvent()); return(success); }
/// <summary> /// Handle internal TestRunner error /// </summary> /// static void HandleInternalException(Exception e) { EventHandlerPipeline.Raise( new ProgramInternalErrorEvent() { Exception = new ExceptionInfo(e) }); if (e is ReflectionTypeLoadException rtle) { foreach (var le in rtle.LoaderExceptions) { EventHandlerPipeline.Raise( new ProgramInternalErrorEvent() { Exception = new ExceptionInfo(le) }); } } }
/// <summary> /// 5. Run test file(s) /// </summary> // static int Main5(IList <string> testFiles) { Banner(); EventHandlerPipeline.Raise(new TestRunBeginEvent() { }); bool success = true; foreach (var testFile in ArgumentParser.TestFiles) { if (!Reinvoke(testFile)) { success = false; } } EventHandlerPipeline.Raise(new TestRunEndEvent() { Result = new TestRunResult() { Success = success } }); return(success ? 0 : 1); }
public static void Run(string assemblyPath) { Guard.NotNull(assemblyPath, nameof(assemblyPath)); EventHandlerPipeline.Raise(new TestAssemblyBeginEvent() { Path = assemblyPath }); do { // // Resolve full path to test assembly file // string fullAssemblyPath = Path.IsPathRooted(assemblyPath) ? assemblyPath : Path.Combine(Environment.CurrentDirectory, assemblyPath); if (!File.Exists(fullAssemblyPath)) { EventHandlerPipeline.Raise(new TestAssemblyNotFoundEvent() { Path = fullAssemblyPath }); break; } // // Load assembly // Assembly assembly; try { assembly = Assembly.LoadFrom(fullAssemblyPath); } catch (BadImageFormatException) { EventHandlerPipeline.Raise(new TestAssemblyNotDotNetEvent() { Path = fullAssemblyPath }); break; } // // Interpret as test assembly // var testAssembly = TestAssembly.TryCreate(assembly); if (testAssembly == null) { EventHandlerPipeline.Raise(new TestAssemblyNotTestEvent() { Path = fullAssemblyPath }); break; } // // Activate the test assembly's .config file if present // ConfigFileSwitcher.SwitchTo(testAssembly.Assembly.Location + ".config"); // // Run [AssemblyInitialize] method // if (!MethodRunner.RunAssemblyInitializeMethod(testAssembly)) { break; } // // Run tests in each [TestClass] // foreach (var testClass in testAssembly.TestClasses) { TestClassRunner.Run(testClass); } // // Run [AssemblyCleanup] method // MethodRunner.RunAssemblyCleanupMethod(testAssembly); }while (false); EventHandlerPipeline.Raise(new TestAssemblyEndEvent()); }
static bool Run( MethodInfo method, object instance, bool takesTestContext, Type expectedException, bool expectedExceptionAllowDerived) { Guard.NotNull(method, nameof(method)); var parameters = takesTestContext ? new object[] { TestContextProxy.Proxy } : null; Exception exception = null; bool exceptionWasExpected = true; var traceListener = new EventTraceListener(); Trace.Listeners.Add(traceListener); try { method.Invoke(instance, parameters); } catch (TargetInvocationException tie) { exception = tie.InnerException; } finally { Trace.Listeners.Remove(traceListener); } if (exception == null) { return(true); } var isExactExpectedException = expectedException != null && exception.GetType() == expectedException; var isDerivedExpectedException = expectedException != null && expectedExceptionAllowDerived && exception.GetType().IsSubclassOf(expectedException); exceptionWasExpected = isExactExpectedException || isDerivedExpectedException; if (exceptionWasExpected) { EventHandlerPipeline.Raise( new MethodExpectedExceptionEvent() { ExpectedFullName = expectedException.FullName, Exception = new ExceptionInfo(exception), }); } else { EventHandlerPipeline.Raise( new MethodUnexpectedExceptionEvent() { Exception = new ExceptionInfo(exception) }); } return(exceptionWasExpected); }