// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 using System.Reflection; using Xunit.Abstractions; using Xunit.Sdk; [assembly: TestFramework("IntegrationTests.Helpers.VerboseTestFramework", "IntegrationTests")] namespace IntegrationTests.Helpers; public class VerboseTestFramework : XunitTestFramework { public VerboseTestFramework(IMessageSink messageSink) : base(messageSink) { } protected override ITestFrameworkExecutor CreateExecutor(AssemblyName assemblyName) { return new VerboseTestExecutor(assemblyName, SourceInformationProvider, DiagnosticMessageSink); } private class VerboseTestExecutor : XunitTestFrameworkExecutor { public VerboseTestExecutor(AssemblyName assemblyName, ISourceInformationProvider sourceInformationProvider, IMessageSink diagnosticMessageSink) : base(assemblyName, sourceInformationProvider, diagnosticMessageSink) { } protected override async void RunTestCases(IEnumerable testCases, IMessageSink executionMessageSink, ITestFrameworkExecutionOptions executionOptions) { using (var assemblyRunner = new VerboseTestAssemblyRunner(TestAssembly, testCases, DiagnosticMessageSink, executionMessageSink, executionOptions)) { await assemblyRunner.RunAsync(); } } } private class VerboseTestAssemblyRunner : XunitTestAssemblyRunner { public VerboseTestAssemblyRunner(ITestAssembly testAssembly, IEnumerable testCases, IMessageSink diagnosticMessageSink, IMessageSink executionMessageSink, ITestFrameworkExecutionOptions executionOptions) : base(testAssembly, testCases, diagnosticMessageSink, executionMessageSink, executionOptions) { } protected override Task RunTestCollectionAsync(IMessageBus messageBus, ITestCollection testCollection, IEnumerable testCases, CancellationTokenSource cancellationTokenSource) { return new VerboseTestCollectionRunner(testCollection, testCases, DiagnosticMessageSink, messageBus, TestCaseOrderer, new ExceptionAggregator(Aggregator), cancellationTokenSource).RunAsync(); } } private class VerboseTestCollectionRunner : XunitTestCollectionRunner { private readonly IMessageSink _diagnosticMessageSink; public VerboseTestCollectionRunner(ITestCollection testCollection, IEnumerable testCases, IMessageSink diagnosticMessageSink, IMessageBus messageBus, ITestCaseOrderer testCaseOrderer, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource) : base(testCollection, testCases, diagnosticMessageSink, messageBus, testCaseOrderer, aggregator, cancellationTokenSource) { _diagnosticMessageSink = diagnosticMessageSink; } protected override Task RunTestClassAsync(ITestClass testClass, IReflectionTypeInfo @class, IEnumerable testCases) { return new VerboseTestClassRunner(testClass, @class, testCases, _diagnosticMessageSink, MessageBus, TestCaseOrderer, new ExceptionAggregator(Aggregator), CancellationTokenSource, CollectionFixtureMappings) .RunAsync(); } } private class VerboseTestClassRunner : XunitTestClassRunner { public VerboseTestClassRunner(ITestClass testClass, IReflectionTypeInfo @class, IEnumerable testCases, IMessageSink diagnosticMessageSink, IMessageBus messageBus, ITestCaseOrderer testCaseOrderer, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource, IDictionary collectionFixtureMappings) : base(testClass, @class, testCases, diagnosticMessageSink, messageBus, testCaseOrderer, aggregator, cancellationTokenSource, collectionFixtureMappings) { } protected override Task RunTestMethodAsync(ITestMethod testMethod, IReflectionMethodInfo method, IEnumerable testCases, object[] constructorArguments) { return new VerboseTestMethodRunner(testMethod, this.Class, method, testCases, this.DiagnosticMessageSink, this.MessageBus, new ExceptionAggregator(this.Aggregator), this.CancellationTokenSource, constructorArguments) .RunAsync(); } } private class VerboseTestMethodRunner : XunitTestMethodRunner { private readonly IMessageSink _diagnosticMessageSink; public VerboseTestMethodRunner(ITestMethod testMethod, IReflectionTypeInfo @class, IReflectionMethodInfo method, IEnumerable testCases, IMessageSink diagnosticMessageSink, IMessageBus messageBus, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource, object[] constructorArguments) : base(testMethod, @class, method, testCases, diagnosticMessageSink, messageBus, aggregator, cancellationTokenSource, constructorArguments) { _diagnosticMessageSink = diagnosticMessageSink; } protected override async Task RunTestCaseAsync(IXunitTestCase testCase) { var parameters = string.Empty; if (testCase.TestMethodArguments != null) { parameters = string.Join(", ", testCase.TestMethodArguments.Select(a => a?.ToString() ?? "null")); } var test = $"{TestMethod.TestClass.Class.Name}.{TestMethod.Method.Name}({parameters})"; _diagnosticMessageSink.OnMessage(new DiagnosticMessage($"=== RUN {test}")); try { var result = await base.RunTestCaseAsync(testCase); var status = result.Failed > 0 ? "FAIL" : "PASS"; _diagnosticMessageSink.OnMessage(new DiagnosticMessage($"--- {status}: {test} ({result.Time:0.00}s)")); return result; } catch (Exception ex) { _diagnosticMessageSink.OnMessage(new DiagnosticMessage($"--- EXPT: {test} ({ex.Message})")); throw; } } } }