using ErsatzTV; using ErsatzTV.Controllers.Api; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.ApplicationParts; using Microsoft.AspNetCore.OpenApi; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Hosting; using Microsoft.OpenApi; using NSubstitute; using NUnit.Framework; namespace ErsatzTV.Tests.Support; /// /// Builds the "v1" OpenAPI document in-process from the real /// registrations, so contract tests validate the document the running app would actually serve — /// including every registered document/operation/schema transformer — rather than a stale committed /// wwwroot/openapi/v1.json that is regenerated out-of-band. Mirrors the DI-only bootstrap that /// ApiControllerSecurityTests uses to inspect MvcOptions. /// public static class GeneratedOpenApiDocument { public static async Task BuildV1Async() { var settings = new Dictionary { ["provider"] = "sqlite", ["ConnectionStrings:Data"] = "Data Source=:memory:" }; IConfiguration configuration = new ConfigurationBuilder().AddInMemoryCollection(settings).Build(); var environment = Substitute.For(); environment.ApplicationName.Returns("ErsatzTV"); environment.EnvironmentName.Returns("Development"); environment.ContentRootPath.Returns(TestContext.CurrentContext.TestDirectory); environment.WebRootPath.Returns(TestContext.CurrentContext.TestDirectory); environment.ContentRootFileProvider.Returns(new NullFileProvider()); environment.WebRootFileProvider.Returns(new NullFileProvider()); var services = new ServiceCollection(); // The host normally provides these; supply them so the OpenAPI document service and the // API-key provider (an operation-transformer dependency) can be constructed. services.AddSingleton(configuration); services.AddLogging(); services.AddSingleton(environment); services.AddSingleton(environment); new Startup(configuration, environment).ConfigureServices(services); // In the running app ErsatzTV is the entry assembly and its controllers are discovered // automatically; under the test runner it is not, so register it as an application part. ApplicationPartManager? partManager = services .FirstOrDefault(d => d.ServiceType == typeof(ApplicationPartManager))?.ImplementationInstance as ApplicationPartManager; if (partManager is not null && !partManager.ApplicationParts.OfType() .Any(p => p.Assembly == typeof(CollectionController).Assembly)) { partManager.ApplicationParts.Add(new AssemblyPart(typeof(CollectionController).Assembly)); } await using ServiceProvider provider = services.BuildServiceProvider(); IOpenApiDocumentProvider documentProvider = provider.GetRequiredKeyedService("v1"); return await documentProvider.GetOpenApiDocumentAsync(); } }