// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.Testing.Platform.Capabilities; using Microsoft.Testing.Platform.Extensions.Messages; using Microsoft.Testing.Platform.Extensions.TestFramework; using Microsoft.Testing.Platform.Extensions.TestHost; using Microsoft.Testing.Platform.Extensions.TestHostControllers; using Microsoft.Testing.Platform.Logging; using Microsoft.Testing.Platform.Services; using Moq; namespace Microsoft.Testing.Platform.UnitTests; [TestClass] public sealed class ServiceProviderTests { private readonly ServiceProvider _serviceProvider = new(); [TestMethod] public void GetRequiredPlatformService_ReturnsServiceFromAnyServiceProvider() { object expected = new(); IServiceProvider provider = new SingleServiceProvider(expected); object actual = provider.GetRequiredPlatformService(); Assert.AreSame(expected, actual); } [TestMethod] public void GetRequiredPlatformService_MissingServiceThrows() { IServiceProvider provider = new SingleServiceProvider(null); Assert.ThrowsExactly(() => provider.GetRequiredPlatformService()); } [TestMethod] public void GetPlatformService_ReturnsServiceOrNullFromAnyServiceProvider() { object expected = new(); IServiceProvider provider = new SingleServiceProvider(expected); Assert.AreSame(expected, provider.GetPlatformService()); Assert.IsNull(new SingleServiceProvider(null).GetPlatformService()); } [TestMethod] public void GetDiagnosticLoggingInformation_ReturnsServiceOrNull() { #pragma warning disable TPEXP // IDiagnosticLoggingInformation is experimental. var information = new Mock(); _serviceProvider.AddService(information.Object); Assert.AreSame(information.Object, _serviceProvider.GetDiagnosticLoggingInformation()); Assert.IsNull(new ServiceProvider().GetDiagnosticLoggingInformation()); #pragma warning restore TPEXP } [TestMethod] public void GetService_InternalExtension_ShouldNotReturn() { _serviceProvider.AddService(new TestHostProcessLifetimeHandler()); Assert.IsNull(_serviceProvider.GetService()); _serviceProvider.AddService(new TestHostEnvironmentVariableProvider()); Assert.IsNull(_serviceProvider.GetService()); _serviceProvider.AddService(new TestSessionLifetimeHandler()); Assert.IsNull(_serviceProvider.GetService()); _serviceProvider.AddService(new DataConsumer()); Assert.IsNull(_serviceProvider.GetService()); _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); Assert.IsNull(_serviceProvider.GetService()); } [TestMethod] public void GetServiceInternal_InternalExtension_ShouldReturn() { _serviceProvider.AddService(new TestHostProcessLifetimeHandler()); Assert.IsNotNull(_serviceProvider.GetServiceInternal()); _serviceProvider.AddService(new TestHostEnvironmentVariableProvider()); Assert.IsNotNull(_serviceProvider.GetServiceInternal()); _serviceProvider.AddService(new TestSessionLifetimeHandler()); Assert.IsNotNull(_serviceProvider.GetServiceInternal()); _serviceProvider.AddService(new DataConsumer()); Assert.IsNotNull(_serviceProvider.GetServiceInternal()); _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); Assert.IsNotNull(_serviceProvider.GetServiceInternal()); } [TestMethod] public void Clone_WithoutFilter_Succeeded() { _serviceProvider.AddService(new TestHostProcessLifetimeHandler()); _serviceProvider.AddService(new TestHostEnvironmentVariableProvider()); _serviceProvider.AddService(new TestSessionLifetimeHandler()); _serviceProvider.AddService(new DataConsumer()); _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); var clonedServiceProvider = (ServiceProvider)_serviceProvider.Clone(); Assert.HasCount(_serviceProvider.Services.Count, clonedServiceProvider.Services); for (int i = 0; i < _serviceProvider.Services.Count; i++) { Assert.AreEqual(_serviceProvider.Services.ToArray()[i], clonedServiceProvider.Services.ToArray()[i]); } } [TestMethod] public void Clone_WithFilter_Succeeded() { _serviceProvider.AddService(new TestHostProcessLifetimeHandler()); _serviceProvider.AddService(new TestHostEnvironmentVariableProvider()); _serviceProvider.AddService(new TestSessionLifetimeHandler()); _serviceProvider.AddService(new DataConsumer()); _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); var clonedServiceProvider = (ServiceProvider)_serviceProvider.Clone(o => o is TestHostProcessLifetimeHandler); Assert.HasCount(1, clonedServiceProvider.Services); Assert.AreEqual(typeof(TestHostProcessLifetimeHandler), _serviceProvider.Services.ToArray()[0].GetType()); } [TestMethod] public void AddService_TestFramework_ShouldFail() => Assert.ThrowsExactly(() => _serviceProvider.AddService(new TestFramework())); [TestMethod] public void TryAddService_TestFramework_ShouldFail() => Assert.ThrowsExactly(() => _serviceProvider.TryAddService(new TestFramework())); [TestMethod] public void AddService_TestFramework_ShouldNotFail() { _serviceProvider.AllowTestAdapterFrameworkRegistration = true; _serviceProvider.AddService(new TestFramework()); } [TestMethod] public void TryAddService_TestFramework_ShouldNotFail() { _serviceProvider.AllowTestAdapterFrameworkRegistration = true; _serviceProvider.TryAddService(new TestFramework()); } [TestMethod] public void AddService_SameInstance_ShouldFail() { TestHostProcessLifetimeHandler instance = new(); _serviceProvider.AddService(instance); _ = Assert.ThrowsExactly(() => _serviceProvider.AddService(instance)); } [TestMethod] public void AddService_SameInstance_ShouldNotFail() { TestHostProcessLifetimeHandler instance = new(); _serviceProvider.AddService(instance); _serviceProvider.AddService(instance, throwIfSameInstanceExit: false); } [TestMethod] public void AddServices_SameInstance_ShouldFail() { TestHostProcessLifetimeHandler instance = new(); _serviceProvider.AddServices([instance]); _ = Assert.ThrowsExactly(() => _serviceProvider.AddServices([instance])); } [TestMethod] public void AddServices_SameInstance_ShouldNotFail() { TestHostProcessLifetimeHandler instance = new(); _serviceProvider.AddServices([instance]); _serviceProvider.AddServices([instance], throwIfSameInstanceExit: false); } [TestMethod] public void TryAddService_SameInstance_ShouldReturnFalse() { TestHostProcessLifetimeHandler instance = new(); Assert.IsTrue(_serviceProvider.TryAddService(instance)); Assert.IsFalse(_serviceProvider.TryAddService(instance)); } [TestMethod] public void ReplaceService_WhenMatchingServiceExists_ReplacesInPlace() { TestSessionLifetimeHandler first = new(); TestSessionLifetimeHandler second = new(); _serviceProvider.AddService(first); _serviceProvider.ReplaceService(second); Assert.HasCount(1, _serviceProvider.Services); Assert.AreSame(second, _serviceProvider.Services.First()); } [TestMethod] public void ReplaceService_WhenNoMatchingServiceExists_AppendsService() { TestSessionLifetimeHandler instance = new(); _serviceProvider.ReplaceService(instance); Assert.HasCount(1, _serviceProvider.Services); Assert.AreSame(instance, _serviceProvider.Services.First()); } [TestMethod] public void ReplaceService_ReplacesFirstMatch_PreservesOtherServices() { TestHostProcessLifetimeHandler other = new(); TestSessionLifetimeHandler first = new(); TestSessionLifetimeHandler second = new(); _serviceProvider.AddService(other); _serviceProvider.AddService(first); _serviceProvider.ReplaceService(second); Assert.HasCount(2, _serviceProvider.Services); Assert.AreSame(other, _serviceProvider.Services.First()); Assert.AreSame(second, _serviceProvider.Services.Last()); } private sealed class SingleServiceProvider(object? service) : IServiceProvider { private readonly object? _service = service; public object? GetService(Type serviceType) => _service is not null && serviceType.IsInstanceOfType(_service) ? _service : null; } [TestMethod] public void ReplaceService_NullService_ThrowsArgumentNullException() => Assert.ThrowsExactly(() => _serviceProvider.ReplaceService(null!)); [TestMethod] public void GetServicesInternal_ExtensionMethod_InternalExtension_ShouldReturn() { _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); Assert.HasCount(2, _serviceProvider.GetServicesInternal()); } [TestMethod] public void GetServicesInternal_InternalExtension_ShouldNotReturn() { _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); Assert.IsEmpty(_serviceProvider.GetServicesInternal(typeof(ITestHostApplicationLifetime), stopAtFirst: false, skipInternalOnlyExtensions: true)); } [TestMethod] public void GetServicesInternal_InternalExtension_ShouldReturn() { _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); Assert.HasCount(2, _serviceProvider.GetServicesInternal(typeof(ITestHostApplicationLifetime), stopAtFirst: false, skipInternalOnlyExtensions: false)); } [TestMethod] public void GetServicesInternal_InternalExtension_FirstOnly_ShouldReturnOne() { _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); Assert.HasCount(1, _serviceProvider.GetServicesInternal(typeof(ITestHostApplicationLifetime), stopAtFirst: true, skipInternalOnlyExtensions: false)); } [TestMethod] public void GetServiceInternal_InternalExtension_ShouldReturnOne() { _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); Assert.IsNotNull(_serviceProvider.GetServiceInternal(typeof(ITestHostApplicationLifetime), skipInternalOnlyExtensions: false)); } [TestMethod] public void GetServiceInternal_InternalExtension_SkipInternalOnlyExtensions_ShouldReturnNull() { _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); _serviceProvider.AddService(new TestApplicationLifecycleCallbacks()); Assert.IsNull(_serviceProvider.GetServiceInternal(typeof(ITestHostApplicationLifetime), skipInternalOnlyExtensions: true)); } private sealed class TestFramework : ITestFramework { public string Uid => throw new NotImplementedException(); public string Version => throw new NotImplementedException(); public string DisplayName => throw new NotImplementedException(); public string Description => throw new NotImplementedException(); public ICapability[] Capabilities => throw new NotImplementedException(); public Task CloseTestSessionAsync(CloseTestSessionContext context) => throw new NotImplementedException(); public Task CreateTestSessionAsync(CreateTestSessionContext context) => throw new NotImplementedException(); public Task ExecuteRequestAsync(ExecuteRequestContext context) => throw new NotImplementedException(); public Task IsEnabledAsync() => throw new NotImplementedException(); } private sealed class TestHostProcessLifetimeHandler : ITestHostProcessLifetimeHandler { public string Uid => throw new NotImplementedException(); public string Version => throw new NotImplementedException(); public string DisplayName => throw new NotImplementedException(); public string Description => throw new NotImplementedException(); public Task BeforeTestHostProcessStartAsync(CancellationToken cancellationToken) => throw new NotImplementedException(); public Task IsEnabledAsync() => throw new NotImplementedException(); public Task OnTestHostProcessExitedAsync(ITestHostProcessInformation testHostProcessInformation, CancellationToken cancellationToken) => throw new NotImplementedException(); public Task OnTestHostProcessStartedAsync(ITestHostProcessInformation testHostProcessInformation, CancellationToken cancellationToken) => throw new NotImplementedException(); } private sealed class TestHostEnvironmentVariableProvider : ITestHostEnvironmentVariableProvider { public string Uid => throw new NotImplementedException(); public string Version => throw new NotImplementedException(); public string DisplayName => throw new NotImplementedException(); public string Description => throw new NotImplementedException(); public Task ValidateTestHostEnvironmentVariablesAsync(IReadOnlyEnvironmentVariables environmentVariables) => throw new NotImplementedException(); public Task IsEnabledAsync() => throw new NotImplementedException(); public Task UpdateAsync(IEnvironmentVariables environmentVariables) => throw new NotImplementedException(); } private sealed class TestSessionLifetimeHandler : ITestSessionLifetimeHandler { public string Uid => throw new NotImplementedException(); public string Version => throw new NotImplementedException(); public string DisplayName => throw new NotImplementedException(); public string Description => throw new NotImplementedException(); public Task IsEnabledAsync() => throw new NotImplementedException(); public Task OnTestSessionFinishingAsync(ITestSessionContext testSessionContext) => throw new NotImplementedException(); public Task OnTestSessionStartingAsync(ITestSessionContext testSessionContext) => throw new NotImplementedException(); } private sealed class DataConsumer : IDataConsumer { public Type[] DataTypesConsumed => throw new NotImplementedException(); public string Uid => throw new NotImplementedException(); public string Version => throw new NotImplementedException(); public string DisplayName => throw new NotImplementedException(); public string Description => throw new NotImplementedException(); public Task ConsumeAsync(IDataProducer dataProducer, IData value, CancellationToken cancellationToken) => throw new NotImplementedException(); public Task IsEnabledAsync() => throw new NotImplementedException(); } private sealed class TestApplicationLifecycleCallbacks : ITestHostApplicationLifetime { public string Uid => throw new NotImplementedException(); public string Version => throw new NotImplementedException(); public string DisplayName => throw new NotImplementedException(); public string Description => throw new NotImplementedException(); public Task AfterRunAsync(int exitCode, CancellationToken cancellationToken) => throw new NotImplementedException(); public Task BeforeRunAsync(CancellationToken cancellationToken) => throw new NotImplementedException(); public Task IsEnabledAsync() => throw new NotImplementedException(); } }