diff --git a/Directory.Packages.props b/Directory.Packages.props
index 1b68ef898..968bb6718 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -4,10 +4,10 @@
true
$(NoWarn);NU1507
-
+
@@ -51,9 +51,8 @@
-
-
+
\ No newline at end of file
diff --git a/azure-pipelines-pr.yml b/azure-pipelines-pr.yml
index 1ee4b5ac5..c55c531b5 100644
--- a/azure-pipelines-pr.yml
+++ b/azure-pipelines-pr.yml
@@ -69,6 +69,30 @@ stages:
steps:
- checkout: self
clean: true
+ # Install additional .NET runtimes needed by integration tests.
+ # The global.json SDK is .NET 11 preview, but the multi-targeted
+ # dotnet-scaffold tool also builds for net8.0, net9.0, and net10.0.
+ # Integration tests invoke 'dotnet run --framework net8.0/net9.0/net10.0'
+ # which requires those runtimes to be present on the agent.
+ - task: UseDotNet@2
+ displayName: Install .NET 8 runtime
+ inputs:
+ packageType: runtime
+ version: 8.x
+ installationPath: $(Build.SourcesDirectory)/.dotnet
+ - task: UseDotNet@2
+ displayName: Install .NET 9 runtime
+ inputs:
+ packageType: runtime
+ version: 9.x
+ installationPath: $(Build.SourcesDirectory)/.dotnet
+ - task: UseDotNet@2
+ displayName: Install .NET 10 runtime
+ inputs:
+ packageType: runtime
+ version: 10.x
+ includePreviewVersions: true
+ installationPath: $(Build.SourcesDirectory)/.dotnet
# Use utility script to run script command dependent on agent OS.
- script: $(_Script)
-configuration $(_BuildConfig)
@@ -94,6 +118,25 @@ stages:
steps:
- checkout: self
clean: true
+ - task: UseDotNet@2
+ displayName: Install .NET 8 runtime
+ inputs:
+ packageType: runtime
+ version: 8.x
+ installationPath: $(Build.SourcesDirectory)/.dotnet
+ - task: UseDotNet@2
+ displayName: Install .NET 9 runtime
+ inputs:
+ packageType: runtime
+ version: 9.x
+ installationPath: $(Build.SourcesDirectory)/.dotnet
+ - task: UseDotNet@2
+ displayName: Install .NET 10 runtime
+ inputs:
+ packageType: runtime
+ version: 10.x
+ includePreviewVersions: true
+ installationPath: $(Build.SourcesDirectory)/.dotnet
- script: eng/common/build.sh
--configuration $(_BuildConfig)
--prepareMachine
@@ -117,6 +160,25 @@ stages:
steps:
- checkout: self
clean: true
+ - task: UseDotNet@2
+ displayName: Install .NET 8 runtime
+ inputs:
+ packageType: runtime
+ version: 8.x
+ installationPath: $(Build.SourcesDirectory)/.dotnet
+ - task: UseDotNet@2
+ displayName: Install .NET 9 runtime
+ inputs:
+ packageType: runtime
+ version: 9.x
+ installationPath: $(Build.SourcesDirectory)/.dotnet
+ - task: UseDotNet@2
+ displayName: Install .NET 10 runtime
+ inputs:
+ packageType: runtime
+ version: 10.x
+ includePreviewVersions: true
+ installationPath: $(Build.SourcesDirectory)/.dotnet
- script: eng/common/build.sh
--configuration $(_BuildConfig)
--prepareMachine
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index f44e9e0c7..93c048ec7 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -86,6 +86,30 @@ extends:
steps:
- checkout: self
clean: true
+ # Install additional .NET runtimes needed by integration tests.
+ # The global.json SDK is .NET 11 preview, but the multi-targeted
+ # dotnet-scaffold tool also builds for net8.0, net9.0, and net10.0.
+ # Integration tests invoke 'dotnet run --framework net8.0/net9.0/net10.0'
+ # which requires those runtimes to be present on the agent.
+ - task: UseDotNet@2
+ displayName: Install .NET 8 runtime
+ inputs:
+ packageType: runtime
+ version: 8.x
+ installationPath: $(Build.SourcesDirectory)/.dotnet
+ - task: UseDotNet@2
+ displayName: Install .NET 9 runtime
+ inputs:
+ packageType: runtime
+ version: 9.x
+ installationPath: $(Build.SourcesDirectory)/.dotnet
+ - task: UseDotNet@2
+ displayName: Install .NET 10 runtime
+ inputs:
+ packageType: runtime
+ version: 10.x
+ includePreviewVersions: true
+ installationPath: $(Build.SourcesDirectory)/.dotnet
# Use utility script to run script command dependent on agent OS.
- script: $(_Script)
-configuration $(_BuildConfig)
diff --git a/src/dotnet-scaffolding/Microsoft.DotNet.Scaffolding.Core/CommandLine/DotnetCommands.cs b/src/dotnet-scaffolding/Microsoft.DotNet.Scaffolding.Core/CommandLine/DotnetCommands.cs
index 0b40cd609..906740d06 100644
--- a/src/dotnet-scaffolding/Microsoft.DotNet.Scaffolding.Core/CommandLine/DotnetCommands.cs
+++ b/src/dotnet-scaffolding/Microsoft.DotNet.Scaffolding.Core/CommandLine/DotnetCommands.cs
@@ -47,6 +47,18 @@ public static bool AddPackage(string packageName, ILogger logger, string? projec
logger.LogInformation($"\nAdding package '{packageDisplayName}'...");
var runner = DotnetCliRunner.CreateDotNet("add", arguments);
+ // Set working directory to the project's directory so that NuGet.config
+ // resolution uses the project's NuGet.config rather than inheriting feeds
+ // from the current working directory (which may have preview/dev feeds).
+ if (!string.IsNullOrEmpty(projectFile))
+ {
+ var projectDir = Path.GetDirectoryName(Path.GetFullPath(projectFile));
+ if (!string.IsNullOrEmpty(projectDir))
+ {
+ runner._psi.WorkingDirectory = projectDir;
+ }
+ }
+
// Buffer the output here because we'll only display it in the failure scenario
var exitCode = runner.ExecuteAndCaptureOutput(out var stdOut, out var stdErr);
diff --git a/src/dotnet-scaffolding/Microsoft.DotNet.Scaffolding.Roslyn/Services/MsBuildInitializer.cs b/src/dotnet-scaffolding/Microsoft.DotNet.Scaffolding.Roslyn/Services/MsBuildInitializer.cs
index 0f9178cc9..b01f2122b 100644
--- a/src/dotnet-scaffolding/Microsoft.DotNet.Scaffolding.Roslyn/Services/MsBuildInitializer.cs
+++ b/src/dotnet-scaffolding/Microsoft.DotNet.Scaffolding.Roslyn/Services/MsBuildInitializer.cs
@@ -20,9 +20,11 @@ public void Initialize()
}
///
- /// find the newest dotnet sdk on disk first, if none found, use the MsBuildLocator.RegisterDefaults().
+ /// Find a compatible dotnet SDK on disk and register its MSBuild.
+ /// Picks the newest SDK whose major version is less than or equal to the current runtime's major version,
+ /// so that loading MSBuild assemblies does not pull in a higher System.Runtime than the runtime supports.
+ /// Falls back to when no compatible SDK is found.
///
- ///
private void RegisterMsbuild()
{
if (!MSBuildLocator.IsRegistered)
@@ -36,16 +38,22 @@ private void RegisterMsbuild()
return;
}
- //register newest MSBuild from the newest dotnet sdk installed.
+ int runtimeMajor = Environment.Version.Major;
+
+ // Find SDKs whose major version is compatible with the running runtime.
+ // A .NET X runtime can safely load MSBuild from SDK version X.y.z (same major)
+ // but NOT from a higher major version (e.g. SDK 11.x on .NET 8 runtime).
var sdkPaths = Directory.GetDirectories(sdkBasePath)
- .Select(d => new { Path = d, new DirectoryInfo(d).Name })
- .Where(d => Version.TryParse(d.Name.Split('-')[0], out _))
- .OrderByDescending(d => Version.Parse(d.Name.Split('-')[0]))
+ .Select(d => new { Path = d, DirName = new DirectoryInfo(d).Name })
+ .Where(d => Version.TryParse(d.DirName.Split('-')[0], out _))
+ .Select(d => new { d.Path, Version = Version.Parse(d.DirName.Split('-')[0]) })
+ .Where(d => d.Version.Major <= runtimeMajor)
+ .OrderByDescending(d => d.Version)
.Select(d => d.Path);
if (!sdkPaths.Any())
{
- _logger.LogInformation($"Could not find a .NET SDK at the default locations.");
+ _logger.LogInformation($"Could not find a .NET SDK compatible with runtime version {Environment.Version} at the default locations.");
MSBuildLocator.RegisterDefaults();
return;
}
@@ -55,7 +63,7 @@ private void RegisterMsbuild()
var msbuildPath = Path.Combine(sdkPath, "MSBuild.dll");
if (File.Exists(msbuildPath))
{
- // Register the latest SDK
+ // Register the best compatible SDK
MSBuildLocator.RegisterMSBuildPath(sdkPath);
break;
}
diff --git a/src/dotnet-scaffolding/dotnet-scaffold/AspNet/Common/ClassAnalyzers.cs b/src/dotnet-scaffolding/dotnet-scaffold/AspNet/Common/ClassAnalyzers.cs
index f00bcf6a1..5f00c59fe 100644
--- a/src/dotnet-scaffolding/dotnet-scaffold/AspNet/Common/ClassAnalyzers.cs
+++ b/src/dotnet-scaffolding/dotnet-scaffold/AspNet/Common/ClassAnalyzers.cs
@@ -46,7 +46,7 @@ internal static DbContextInfo GetDbContextInfo(
dbContextInfo.NewDbSetStatement = modelInfo is null ?
string.Empty : $"public DbSet<{modelInfo.ModelFullName}> {modelInfo.ModelTypeName} {{ get; set; }} = default!;";
dbContextInfo.DbContextClassName = dbContextClassName;
- dbContextInfo.DbContextClassPath = CommandHelpers.GetNewFilePath(projectPath, dbContextClassName);
+ dbContextInfo.DbContextClassPath = AspNetDbContextHelper.GetIdentityDataContextPath(projectPath, dbContextClassName);
dbContextInfo.DatabaseProvider = dbProvider;
dbContextInfo.EntitySetVariableName = modelInfo?.ModelTypeName;
}
diff --git a/src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net8.0/CodeModificationConfigs/minimalApiChanges.json b/src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net8.0/CodeModificationConfigs/minimalApiChanges.json
index db41bc499..183bc5051 100644
--- a/src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net8.0/CodeModificationConfigs/minimalApiChanges.json
+++ b/src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net8.0/CodeModificationConfigs/minimalApiChanges.json
@@ -14,7 +14,40 @@
}
}
]
- },
+ }
+ }
+ },
+ {
+ "FileName": "Program.cs",
+ "Usings": [
+ "Microsoft.EntityFrameworkCore"
+ ],
+ "Options": [
+ "EfScenario"
+ ],
+ "Methods": {
+ "Global": {
+ "CodeChanges": [
+ {
+ "InsertAfter": "WebApplication.CreateBuilder",
+ "CheckBlock": "builder.Configuration.GetConnectionString",
+ "Block": "\nvar connectionString = builder.Configuration.GetConnectionString(\"$(ConnectionStringName)\") ?? throw new InvalidOperationException(\"Connection string '$(ConnectionStringName)' not found.\")"
+ },
+ {
+ "InsertAfter": "builder.Configuration.GetConnectionString",
+ "CheckBlock": "builder.Services.AddDbContext",
+ "Block": "builder.Services.AddDbContext<$(DbContextName)>(options => options.$(UseDbMethod))",
+ "LeadingTrivia": {
+ "Newline": true
+ }
+ }
+ ]
+ }
+ }
+ },
+ {
+ "FileName": "Program.cs",
+ "Methods": {
"OpenApi": {
"CodeChanges": [
{
diff --git a/src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net9.0/EfController/MvcEfController.cs b/src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net9.0/EfController/MvcEfController.cs
index f01517774..1cb03dd8a 100644
--- a/src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net9.0/EfController/MvcEfController.cs
+++ b/src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net9.0/EfController/MvcEfController.cs
@@ -103,7 +103,9 @@ public virtual string TransformText()
[ValidateAntiForgeryToken]
public async Task Create([Bind(""Title,ReleaseDate,Genre,Price"")] ");
this.Write(this.ToStringHelper.ToStringWithCulture(modelName));
- this.Write(" movie)\r\n {\r\n if (ModelState.IsValid)\r\n {\r\n _context." +
+ this.Write(" ");
+ this.Write(this.ToStringHelper.ToStringWithCulture(modelNameLowerInv));
+ this.Write(")\r\n {\r\n if (ModelState.IsValid)\r\n {\r\n _context." +
"Add(");
this.Write(this.ToStringHelper.ToStringWithCulture(modelNameLowerInv));
this.Write(");\r\n await _context.SaveChangesAsync();\r\n return RedirectTo" +
@@ -141,7 +143,9 @@ public virtual string TransformText()
this.Write(this.ToStringHelper.ToStringWithCulture(primaryKeyNameLowerInv));
this.Write(", [Bind(\"Id,Title,ReleaseDate,Genre,Price\")] ");
this.Write(this.ToStringHelper.ToStringWithCulture(modelName));
- this.Write(" movie)\r\n {\r\n if (");
+ this.Write(" ");
+ this.Write(this.ToStringHelper.ToStringWithCulture(modelNameLowerInv));
+ this.Write(")\r\n {\r\n if (");
this.Write(this.ToStringHelper.ToStringWithCulture(primaryKeyNameLowerInv));
this.Write(" != ");
this.Write(this.ToStringHelper.ToStringWithCulture(modelNameLowerInv));
diff --git a/src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net9.0/EfController/MvcEfController.tt b/src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net9.0/EfController/MvcEfController.tt
index c367f4cc9..25c781d77 100644
--- a/src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net9.0/EfController/MvcEfController.tt
+++ b/src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net9.0/EfController/MvcEfController.tt
@@ -76,7 +76,7 @@ public class <#= Model.ControllerName #> : Controller
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
- public async Task Create([Bind("Title,ReleaseDate,Genre,Price")] <#= modelName #> movie)
+ public async Task Create([Bind("Title,ReleaseDate,Genre,Price")] <#= modelName #> <#= modelNameLowerInv #>)
{
if (ModelState.IsValid)
{
@@ -108,7 +108,7 @@ public class <#= Model.ControllerName #> : Controller
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
- public async Task Edit(<#= primaryKeyTypeName #>? <#= primaryKeyNameLowerInv #>, [Bind("Id,Title,ReleaseDate,Genre,Price")] <#= modelName #> movie)
+ public async Task Edit(<#= primaryKeyTypeName #>? <#= primaryKeyNameLowerInv #>, [Bind("Id,Title,ReleaseDate,Genre,Price")] <#= modelName #> <#= modelNameLowerInv #>)
{
if (<#= primaryKeyNameLowerInv #> != <#= modelNameLowerInv #>.<#= primaryKeyName #>)
{
diff --git a/src/dotnet-scaffolding/dotnet-scaffold/dotnet-scaffold.csproj b/src/dotnet-scaffolding/dotnet-scaffold/dotnet-scaffold.csproj
index c271bc622..a98325db1 100644
--- a/src/dotnet-scaffolding/dotnet-scaffold/dotnet-scaffold.csproj
+++ b/src/dotnet-scaffolding/dotnet-scaffold/dotnet-scaffold.csproj
@@ -108,6 +108,60 @@
PreserveNewest
AspNet\Templates\net8.0\%(RecursiveDir)%(Filename)%(Extension)
+
+
+ PreserveNewest
+ AspNet\Templates\net8.0\EfController\%(Filename)%(Extension)
+
+
+ PreserveNewest
+ AspNet\Templates\net8.0\RazorPages\%(Filename)%(Extension)
+
+
+ PreserveNewest
+ AspNet\Templates\net8.0\Views\%(Filename)%(Extension)
+
+
+ PreserveNewest
+ AspNet\Templates\net8.0\MinimalApi\%(Filename)%(Extension)
+
+
+ PreserveNewest
+ AspNet\Templates\net8.0\Identity\Pages\%(RecursiveDir)%(Filename)%(Extension)
+
+
+ PreserveNewest
+ AspNet\Templates\net8.0\BlazorIdentity\Pages\AccessDenied.tt
+
+
+ PreserveNewest
+ AspNet\Templates\net8.0\Files\ApplicationUser.tt
+
+
+ PreserveNewest
+ AspNet\Templates\net8.0\Files\_ValidationScriptsPartial.cshtml
+
+
+
+ PreserveNewest
+ AspNet\Templates\net8.0\CodeModificationConfigs\efControllerChanges.json
+
+
+ PreserveNewest
+ AspNet\Templates\net8.0\CodeModificationConfigs\identityChanges.json
+
+
+ PreserveNewest
+ AspNet\Templates\net8.0\CodeModificationConfigs\razorPagesChanges.json
+
PreserveNewest
@@ -151,8 +205,64 @@
+
+
+ PreserveNewest
+ AspNet\Templates\net8.0\DbContext\%(Filename)%(Extension)
+
+
+
+ PreserveNewest
+ AspNet\Templates\net8.0\DbContext\NewDbContext.tt
+
+
+ PreserveNewest
+ AspNet\Templates\net9.0\DbContext\%(Filename)%(Extension)
+
+
+ PreserveNewest
+ AspNet\Templates\net10.0\DbContext\%(Filename)%(Extension)
+
+
+ PreserveNewest
+ AspNet\Templates\net11.0\DbContext\%(Filename)%(Extension)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_AspNetConfigs_net8 Include="$(OutputPath)AspNet\Templates\net8.0\CodeModificationConfigs\*.json" />
+ <_AspNetConfigs_net9 Include="$(OutputPath)AspNet\Templates\net9.0\CodeModificationConfigs\*.json" />
+ <_AspNetConfigs_net10 Include="$(OutputPath)AspNet\Templates\net10.0\CodeModificationConfigs\*.json" />
+ <_AspNetConfigs_net11 Include="$(OutputPath)AspNet\Templates\net11.0\CodeModificationConfigs\*.json" />
+
+
+
+
+
+
+
diff --git a/test-results.txt b/test-results.txt
new file mode 100644
index 000000000..c8ea345ca
Binary files /dev/null and b/test-results.txt differ
diff --git a/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/ApiControllerIntegrationTestsBase.cs b/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/ApiControllerIntegrationTestsBase.cs
new file mode 100644
index 000000000..801643103
--- /dev/null
+++ b/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/ApiControllerIntegrationTestsBase.cs
@@ -0,0 +1,446 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using Microsoft.DotNet.Tools.Scaffold.Tests.Helpers;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+using Microsoft.DotNet.Scaffolding.Core.Scaffolders;
+using Microsoft.DotNet.Scaffolding.Internal.Services;
+using Microsoft.DotNet.Tools.Scaffold.AspNet;
+using Microsoft.DotNet.Tools.Scaffold.AspNet.Commands;
+using Microsoft.DotNet.Tools.Scaffold.AspNet.Common;
+using Microsoft.DotNet.Tools.Scaffold.AspNet.ScaffoldSteps;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using Moq;
+using Xunit;
+
+namespace Microsoft.DotNet.Tools.Scaffold.Tests.AspNet.Integration;
+
+///
+/// Shared base class for API Controller with EF (CRUD) integration tests across .NET versions.
+///
+public abstract class ApiControllerIntegrationTestsBase : IDisposable
+{
+ protected abstract string TargetFramework { get; }
+ protected abstract string TestClassName { get; }
+
+ protected readonly string _testDirectory;
+ protected readonly string _testProjectDir;
+ protected readonly string _testProjectPath;
+ protected readonly Mock _mockFileSystem;
+ protected readonly TestTelemetryService _testTelemetryService;
+ protected readonly Mock _mockScaffolder;
+ protected readonly ScaffolderContext _context;
+
+ protected ApiControllerIntegrationTestsBase()
+ {
+ _testDirectory = Path.Combine(Path.GetTempPath(), TestClassName, Guid.NewGuid().ToString());
+ _testProjectDir = Path.Combine(_testDirectory, "TestProject");
+ _testProjectPath = Path.Combine(_testProjectDir, "TestProject.csproj");
+ Directory.CreateDirectory(_testProjectDir);
+
+ _mockFileSystem = new Mock();
+ _testTelemetryService = new TestTelemetryService();
+
+ _mockScaffolder = new Mock();
+ _mockScaffolder.Setup(s => s.DisplayName).Returns(AspnetStrings.Api.ApiControllerCrudDisplayName);
+ _mockScaffolder.Setup(s => s.Name).Returns(AspnetStrings.Api.ApiControllerCrud);
+ _context = new ScaffolderContext(_mockScaffolder.Object);
+ }
+
+ public void Dispose()
+ {
+ if (Directory.Exists(_testDirectory))
+ {
+ try { Directory.Delete(_testDirectory, recursive: true); }
+ catch { /* best-effort cleanup */ }
+ }
+ }
+
+ protected string ProjectContent => $@"
+
+ {TargetFramework}
+ enable
+
+";
+
+ #region ValidateEfControllerStep — Validation Logic
+
+ [Fact]
+ public async Task ValidateEfControllerStep_FailsWithNullProject()
+ {
+ var step = CreateValidateEfControllerStep();
+ step.Project = null;
+ step.Model = "Product";
+ step.ControllerName = "ProductsController";
+ step.ControllerType = "API";
+ step.DataContext = "AppDbContext";
+ step.DatabaseProvider = PackageConstants.EfConstants.SQLite;
+
+ var result = await step.ExecuteAsync(_context);
+ Assert.False(result);
+ }
+
+ [Fact]
+ public async Task ValidateEfControllerStep_FailsWithEmptyProject()
+ {
+ var step = CreateValidateEfControllerStep();
+ step.Project = string.Empty;
+ step.Model = "Product";
+ step.ControllerName = "ProductsController";
+ step.ControllerType = "API";
+ step.DataContext = "AppDbContext";
+ step.DatabaseProvider = PackageConstants.EfConstants.SQLite;
+
+ var result = await step.ExecuteAsync(_context);
+ Assert.False(result);
+ }
+
+ [Fact]
+ public async Task ValidateEfControllerStep_FailsWithNonExistentProject()
+ {
+ _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
+
+ var step = CreateValidateEfControllerStep();
+ step.Project = @"C:\NonExistent\Project.csproj";
+ step.Model = "Product";
+ step.ControllerName = "ProductsController";
+ step.ControllerType = "API";
+ step.DataContext = "AppDbContext";
+ step.DatabaseProvider = PackageConstants.EfConstants.SQLite;
+
+ var result = await step.ExecuteAsync(_context);
+ Assert.False(result);
+ }
+
+ [Fact]
+ public async Task ValidateEfControllerStep_FailsWithNullModel()
+ {
+ _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
+
+ var step = CreateValidateEfControllerStep();
+ step.Project = _testProjectPath;
+ step.Model = null;
+ step.ControllerName = "ProductsController";
+ step.ControllerType = "API";
+ step.DataContext = "AppDbContext";
+ step.DatabaseProvider = PackageConstants.EfConstants.SQLite;
+
+ var result = await step.ExecuteAsync(_context);
+ Assert.False(result);
+ }
+
+ [Fact]
+ public async Task ValidateEfControllerStep_FailsWithEmptyModel()
+ {
+ _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
+
+ var step = CreateValidateEfControllerStep();
+ step.Project = _testProjectPath;
+ step.Model = string.Empty;
+ step.ControllerName = "ProductsController";
+ step.ControllerType = "API";
+ step.DataContext = "AppDbContext";
+ step.DatabaseProvider = PackageConstants.EfConstants.SQLite;
+
+ var result = await step.ExecuteAsync(_context);
+ Assert.False(result);
+ }
+
+ [Fact]
+ public async Task ValidateEfControllerStep_FailsWithNullControllerName()
+ {
+ _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
+
+ var step = CreateValidateEfControllerStep();
+ step.Project = _testProjectPath;
+ step.Model = "Product";
+ step.ControllerName = null;
+ step.ControllerType = "API";
+ step.DataContext = "AppDbContext";
+ step.DatabaseProvider = PackageConstants.EfConstants.SQLite;
+
+ var result = await step.ExecuteAsync(_context);
+ Assert.False(result);
+ }
+
+ [Fact]
+ public async Task ValidateEfControllerStep_FailsWithEmptyControllerName()
+ {
+ _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
+
+ var step = CreateValidateEfControllerStep();
+ step.Project = _testProjectPath;
+ step.Model = "Product";
+ step.ControllerName = string.Empty;
+ step.ControllerType = "API";
+ step.DataContext = "AppDbContext";
+ step.DatabaseProvider = PackageConstants.EfConstants.SQLite;
+
+ var result = await step.ExecuteAsync(_context);
+ Assert.False(result);
+ }
+
+ [Fact]
+ public async Task ValidateEfControllerStep_FailsWithNullControllerType()
+ {
+ _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
+
+ var step = CreateValidateEfControllerStep();
+ step.Project = _testProjectPath;
+ step.Model = "Product";
+ step.ControllerName = "ProductsController";
+ step.ControllerType = null;
+ step.DataContext = "AppDbContext";
+ step.DatabaseProvider = PackageConstants.EfConstants.SQLite;
+
+ var result = await step.ExecuteAsync(_context);
+ Assert.False(result);
+ }
+
+ [Fact]
+ public async Task ValidateEfControllerStep_FailsWithNullDataContext()
+ {
+ _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
+
+ var step = CreateValidateEfControllerStep();
+ step.Project = _testProjectPath;
+ step.Model = "Product";
+ step.ControllerName = "ProductsController";
+ step.ControllerType = "API";
+ step.DataContext = null;
+ step.DatabaseProvider = PackageConstants.EfConstants.SQLite;
+
+ var result = await step.ExecuteAsync(_context);
+ Assert.False(result);
+ }
+
+ [Fact]
+ public async Task ValidateEfControllerStep_FailsWithEmptyDataContext()
+ {
+ _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
+
+ var step = CreateValidateEfControllerStep();
+ step.Project = _testProjectPath;
+ step.Model = "Product";
+ step.ControllerName = "ProductsController";
+ step.ControllerType = "API";
+ step.DataContext = string.Empty;
+ step.DatabaseProvider = PackageConstants.EfConstants.SQLite;
+
+ var result = await step.ExecuteAsync(_context);
+ Assert.False(result);
+ }
+
+ #endregion
+
+ #region Telemetry
+
+ [Fact]
+ public async Task ValidateEfControllerStep_TracksTelemetry_OnNullProjectFailure()
+ {
+ var step = CreateValidateEfControllerStep();
+ step.Project = null;
+ step.Model = "Product";
+ step.ControllerName = "ProductsController";
+ step.ControllerType = "API";
+ step.DataContext = "AppDbContext";
+
+ await step.ExecuteAsync(_context);
+
+ Assert.Single(_testTelemetryService.TrackedEvents);
+ }
+
+ [Fact]
+ public async Task ValidateEfControllerStep_TracksTelemetry_OnNullModelFailure()
+ {
+ _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
+
+ var step = CreateValidateEfControllerStep();
+ step.Project = _testProjectPath;
+ step.Model = null;
+ step.ControllerName = "ProductsController";
+ step.ControllerType = "API";
+ step.DataContext = "AppDbContext";
+
+ await step.ExecuteAsync(_context);
+
+ Assert.Single(_testTelemetryService.TrackedEvents);
+ }
+
+ [Fact]
+ public async Task ValidateEfControllerStep_TracksTelemetry_OnNullControllerNameFailure()
+ {
+ _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
+
+ var step = CreateValidateEfControllerStep();
+ step.Project = _testProjectPath;
+ step.Model = "Product";
+ step.ControllerName = null;
+ step.ControllerType = "API";
+ step.DataContext = "AppDbContext";
+
+ await step.ExecuteAsync(_context);
+
+ Assert.Single(_testTelemetryService.TrackedEvents);
+ }
+
+ #endregion
+
+ #region Validation Theories
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ public async Task ValidateEfControllerStep_FailsWithInvalidModel(string? model)
+ {
+ _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
+
+ var step = CreateValidateEfControllerStep();
+ step.Project = _testProjectPath;
+ step.Model = model;
+ step.ControllerName = "ProductsController";
+ step.ControllerType = "API";
+ step.DataContext = "AppDbContext";
+ step.DatabaseProvider = PackageConstants.EfConstants.SQLite;
+
+ var result = await step.ExecuteAsync(_context);
+ Assert.False(result);
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ public async Task ValidateEfControllerStep_FailsWithInvalidControllerName(string? controllerName)
+ {
+ _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
+
+ var step = CreateValidateEfControllerStep();
+ step.Project = _testProjectPath;
+ step.Model = "Product";
+ step.ControllerName = controllerName;
+ step.ControllerType = "API";
+ step.DataContext = "AppDbContext";
+ step.DatabaseProvider = PackageConstants.EfConstants.SQLite;
+
+ var result = await step.ExecuteAsync(_context);
+ Assert.False(result);
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ public async Task ValidateEfControllerStep_FailsWithInvalidDataContext(string? dataContext)
+ {
+ _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
+
+ var step = CreateValidateEfControllerStep();
+ step.Project = _testProjectPath;
+ step.Model = "Product";
+ step.ControllerName = "ProductsController";
+ step.ControllerType = "API";
+ step.DataContext = dataContext;
+ step.DatabaseProvider = PackageConstants.EfConstants.SQLite;
+
+ var result = await step.ExecuteAsync(_context);
+ Assert.False(result);
+ }
+
+ #endregion
+
+ #region EF Providers — Structure Tests
+
+ [Fact]
+ public void EfPackagesDict_ContainsAllFourProviders()
+ {
+ Assert.Equal(4, PackageConstants.EfConstants.EfPackagesDict.Count);
+ Assert.True(PackageConstants.EfConstants.EfPackagesDict.ContainsKey(PackageConstants.EfConstants.SQLite));
+ Assert.True(PackageConstants.EfConstants.EfPackagesDict.ContainsKey(PackageConstants.EfConstants.SQLite));
+ Assert.True(PackageConstants.EfConstants.EfPackagesDict.ContainsKey(PackageConstants.EfConstants.CosmosDb));
+ Assert.True(PackageConstants.EfConstants.EfPackagesDict.ContainsKey(PackageConstants.EfConstants.Postgres));
+ }
+
+ [Fact]
+ public void UseDatabaseMethods_HasAllFourProviders()
+ {
+ Assert.Equal(4, PackageConstants.EfConstants.UseDatabaseMethods.Count);
+ }
+
+ #endregion
+
+ #region EfController Templates
+
+ [Fact]
+ public void EfControllerTemplates_FolderExists()
+ {
+ var basePath = GetActualTemplatesBasePath();
+ var efControllerDir = Path.Combine(basePath, TargetFramework, "EfController");
+ Assert.True(Directory.Exists(efControllerDir),
+ $"EfController template folder should exist for {TargetFramework}");
+ }
+
+
+ #endregion
+
+ #region Template Root — Expected Scaffolder Folders
+
+ [Theory]
+ [InlineData("BlazorCrud")]
+ [InlineData("BlazorIdentity")]
+ [InlineData("CodeModificationConfigs")]
+ [InlineData("EfController")]
+ [InlineData("Files")]
+ [InlineData("Identity")]
+ [InlineData("MinimalApi")]
+ [InlineData("RazorPages")]
+ [InlineData("Views")]
+ public void Templates_HasExpectedScaffolderFolder(string folderName)
+ {
+ var basePath = GetActualTemplatesBasePath();
+ var folderPath = Path.Combine(basePath, TargetFramework, folderName);
+ Assert.True(Directory.Exists(folderPath),
+ $"Expected template folder '{folderName}' not found for {TargetFramework}");
+ }
+
+ #endregion
+
+ #region Helper Methods
+
+ private ValidateEfControllerStep CreateValidateEfControllerStep()
+ {
+ return new ValidateEfControllerStep(
+ _mockFileSystem.Object,
+ NullLogger.Instance,
+ _testTelemetryService);
+ }
+
+ protected static string GetActualTemplatesBasePath()
+ {
+ var assemblyLocation = Assembly.GetExecutingAssembly().Location;
+ var assemblyDirectory = Path.GetDirectoryName(assemblyLocation);
+ var basePath = Path.Combine(assemblyDirectory!, "..", "..", "..", "..", "..", "src", "dotnet-scaffolding", "dotnet-scaffold", "AspNet", "Templates");
+ return Path.GetFullPath(basePath);
+ }
+
+ protected Task<(int ExitCode, string Output, string Error)> RunBuildAsync(string workingDirectory)
+ => ScaffoldCliHelper.RunBuildForFrameworkAsync(workingDirectory, TargetFramework);
+
+ protected class TestTelemetryService : ITelemetryService
+ {
+ public List<(string EventName, IReadOnlyDictionary Properties, IReadOnlyDictionary Measures)> TrackedEvents { get; } = new();
+ public void TrackEvent(string eventName, IReadOnlyDictionary? properties = null, IReadOnlyDictionary? measures = null)
+ {
+ TrackedEvents.Add((eventName, properties ?? new Dictionary(), measures ?? new Dictionary()));
+ }
+
+ public void Flush() { }
+ }
+
+ #endregion
+}
diff --git a/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/ApiControllerNet10IntegrationTests.cs b/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/ApiControllerNet10IntegrationTests.cs
index 4873472ad..38b2b706e 100644
--- a/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/ApiControllerNet10IntegrationTests.cs
+++ b/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/ApiControllerNet10IntegrationTests.cs
@@ -1,1743 +1,55 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System;
-using System.Collections.Generic;
using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Threading;
using System.Threading.Tasks;
-using Microsoft.DotNet.Scaffolding.Core.Builder;
-using Microsoft.DotNet.Scaffolding.Core.ComponentModel;
-using Microsoft.DotNet.Scaffolding.Core.Scaffolders;
-using Microsoft.DotNet.Scaffolding.Core.Steps;
-using Microsoft.DotNet.Scaffolding.Internal.Services;
-using Microsoft.DotNet.Scaffolding.Internal.Telemetry;
-using Microsoft.DotNet.Scaffolding.TextTemplating;
-using Microsoft.DotNet.Tools.Scaffold.AspNet;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.Commands;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.Common;
-using AspNetConstants = Microsoft.DotNet.Tools.Scaffold.AspNet.Common.Constants;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.Helpers;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.Models;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.ScaffoldSteps;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.ScaffoldSteps.Settings;
-using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Logging.Abstractions;
-using Moq;
+using Microsoft.DotNet.Tools.Scaffold.Tests.Helpers;
using Xunit;
namespace Microsoft.DotNet.Tools.Scaffold.Tests.AspNet.Integration.API;
-///
-/// Integration tests for the API Controller CRUD (apicontroller-crud) scaffolder targeting .NET 10.
-/// Validates scaffolder definition constants, ValidateEfControllerStep validation logic,
-/// EfControllerModel/EfControllerSettings/EfWithModelStepSettings/BaseSettings properties,
-/// EfControllerHelper template resolution, template folder verification, code modification configs,
-/// package constants, pipeline registration, step dependencies, telemetry tracking,
-/// TFM availability, builder extensions, and database provider support.
-/// The API Controller CRUD scaffolder is available for all supported TFMs including .NET 10.
-/// .NET 10 EfController templates use .tt text template format (ApiEfController.tt, MvcEfController.tt)
-/// compiled to the Templates.net10.EfController namespace. Unlike net9.0 (whose .cs files are excluded),
-/// net10.0 EfController .cs files are explicitly re-included via Compile Update in the csproj,
-/// making Templates.net10.EfController the canonical compiled template types used by GetCrudControllerType.
-///
-public class ApiControllerNet10IntegrationTests : IDisposable
+public class ApiControllerNet10IntegrationTests : ApiControllerIntegrationTestsBase
{
- private const string TargetFramework = "net10.0";
- private readonly string _testDirectory;
- private readonly string _testProjectDir;
- private readonly string _testProjectPath;
- private readonly Mock _mockFileSystem;
- private readonly TestTelemetryService _testTelemetryService;
- private readonly Mock _mockScaffolder;
- private readonly ScaffolderContext _context;
-
- public ApiControllerNet10IntegrationTests()
- {
- _testDirectory = Path.Combine(Path.GetTempPath(), "ApiControllerNet10IntegrationTests", Guid.NewGuid().ToString());
- _testProjectDir = Path.Combine(_testDirectory, "TestProject");
- _testProjectPath = Path.Combine(_testProjectDir, "TestProject.csproj");
- Directory.CreateDirectory(_testProjectDir);
-
- _mockFileSystem = new Mock();
- _testTelemetryService = new TestTelemetryService();
- _mockScaffolder = new Mock();
- _mockScaffolder.Setup(s => s.DisplayName).Returns(AspnetStrings.Api.ApiControllerCrudDisplayName);
- _mockScaffolder.Setup(s => s.Name).Returns(AspnetStrings.Api.ApiControllerCrud);
- _context = new ScaffolderContext(_mockScaffolder.Object);
- }
-
- public void Dispose()
- {
- if (Directory.Exists(_testDirectory))
- {
- try { Directory.Delete(_testDirectory, recursive: true); }
- catch { /* best-effort cleanup */ }
- }
- }
-
- #region Constants & Scaffolder Definition — API Controller CRUD
-
- [Fact]
- public void ScaffolderName_IsApiControllerCrud_Net10()
- {
- Assert.Equal("apicontroller-crud", AspnetStrings.Api.ApiControllerCrud);
- }
-
- [Fact]
- public void ScaffolderDisplayName_IsApiControllerCrudDisplayName_Net10()
- {
- Assert.Equal("API Controller with actions, using Entity Framework (CRUD)", AspnetStrings.Api.ApiControllerCrudDisplayName);
- }
-
- [Fact]
- public void ScaffolderDescription_IsApiControllerCrudDescription_Net10()
- {
- Assert.Equal("Create an API controller with REST actions to create, read, update, delete, and list entities", AspnetStrings.Api.ApiControllerCrudDescription);
- }
-
- [Fact]
- public void ScaffolderCategory_IsAPI_Net10()
- {
- Assert.Equal("API", AspnetStrings.Catagories.API);
- }
-
- [Fact]
- public void ScaffolderExample1_ContainsApiControllerCrudCommand_Net10()
- {
- Assert.Contains("apicontroller-crud", AspnetStrings.Api.ApiControllerCrudExample1);
- }
-
- [Fact]
- public void ScaffolderExample1_ContainsRequiredOptions_Net10()
- {
- Assert.Contains("--project", AspnetStrings.Api.ApiControllerCrudExample1);
- Assert.Contains("--model", AspnetStrings.Api.ApiControllerCrudExample1);
- Assert.Contains("--controller-name", AspnetStrings.Api.ApiControllerCrudExample1);
- Assert.Contains("--data-context", AspnetStrings.Api.ApiControllerCrudExample1);
- Assert.Contains("--database-provider", AspnetStrings.Api.ApiControllerCrudExample1);
- }
-
- [Fact]
- public void ScaffolderExample2_ContainsApiControllerCrudCommand_Net10()
- {
- Assert.Contains("apicontroller-crud", AspnetStrings.Api.ApiControllerCrudExample2);
- }
-
- [Fact]
- public void ScaffolderExample2_ContainsPrerelease_Net10()
- {
- Assert.Contains("--prerelease", AspnetStrings.Api.ApiControllerCrudExample2);
- }
-
- [Fact]
- public void ScaffolderExample1Description_MentionsCrudOperations_Net10()
- {
- Assert.Contains("CRUD", AspnetStrings.Api.ApiControllerCrudExample1Description);
- }
-
- [Fact]
- public void ScaffolderExample2Description_MentionsPostgreSQL_Net10()
- {
- Assert.Contains("PostgreSQL", AspnetStrings.Api.ApiControllerCrudExample2Description);
- }
-
- #endregion
-
- #region Constants & Scaffolder Definition — MVC Controller CRUD
-
- [Fact]
- public void MVC_ScaffolderName_IsMvcControllerCrud_Net10()
- {
- Assert.Equal("mvccontroller-crud", AspnetStrings.MVC.ControllerCrud);
- }
-
- [Fact]
- public void MVC_ScaffolderDisplayName_IsMvcControllerCrudDisplayName_Net10()
- {
- Assert.Equal("MVC Controller with views, using Entity Framework (CRUD)", AspnetStrings.MVC.CrudDisplayName);
- }
-
- [Fact]
- public void MVC_ScaffolderDescription_IsMvcControllerCrudDescription_Net10()
- {
- Assert.Equal("Create a MVC controller with read/write actions and views using Entity Framework", AspnetStrings.MVC.CrudDescription);
- }
-
- [Fact]
- public void MVC_ScaffolderCategory_IsMVC_Net10()
- {
- Assert.Equal("MVC", AspnetStrings.Catagories.MVC);
- }
-
- [Fact]
- public void MVC_ScaffolderExample1_ContainsMvcControllerCrudCommand_Net10()
- {
- Assert.Contains("mvccontroller-crud", AspnetStrings.MVC.ControllerCrudExample1);
- }
-
- [Fact]
- public void MVC_ScaffolderExample1_ContainsViewsOption_Net10()
- {
- Assert.Contains("--views", AspnetStrings.MVC.ControllerCrudExample1);
- }
-
- #endregion
-
- #region CLI Options
-
- [Fact]
- public void CliOption_ProjectOption_IsCorrect_Net10()
- {
- Assert.Equal("--project", AspNetConstants.CliOptions.ProjectCliOption);
- }
-
- [Fact]
- public void CliOption_ModelOption_IsCorrect_Net10()
- {
- Assert.Equal("--model", AspNetConstants.CliOptions.ModelCliOption);
- }
-
- [Fact]
- public void CliOption_DataContextOption_IsCorrect_Net10()
- {
- Assert.Equal("--dataContext", AspNetConstants.CliOptions.DataContextOption);
- }
-
- [Fact]
- public void CliOption_DbProviderOption_IsCorrect_Net10()
- {
- Assert.Equal("--dbProvider", AspNetConstants.CliOptions.DbProviderOption);
- }
-
- [Fact]
- public void CliOption_ControllerNameOption_IsCorrect_Net10()
- {
- Assert.Equal("--controller", AspNetConstants.CliOptions.ControllerNameOption);
- }
-
- [Fact]
- public void CliOption_PrereleaseOption_IsCorrect_Net10()
- {
- Assert.Equal("--prerelease", AspNetConstants.CliOptions.PrereleaseCliOption);
- }
-
- [Fact]
- public void CliOption_ViewsOption_IsCorrect_Net10()
- {
- Assert.Equal("--views", AspNetConstants.CliOptions.ViewsOption);
- }
-
- #endregion
-
- #region AspNetOptions for EfController
-
- [Fact]
- public void AspNetOptions_HasModelNameProperty_Net10()
- {
- var prop = typeof(AspNetOptions).GetProperty("ModelName");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasControllerNameProperty_Net10()
- {
- var prop = typeof(AspNetOptions).GetProperty("ControllerName");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasDataContextClassRequiredProperty_Net10()
- {
- var prop = typeof(AspNetOptions).GetProperty("DataContextClassRequired");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasDatabaseProviderRequiredProperty_Net10()
- {
- var prop = typeof(AspNetOptions).GetProperty("DatabaseProviderRequired");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasPrereleaseProperty_Net10()
- {
- var prop = typeof(AspNetOptions).GetProperty("Prerelease");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasViewsProperty_Net10()
- {
- var prop = typeof(AspNetOptions).GetProperty("Views");
- Assert.NotNull(prop);
- }
-
- #endregion
-
- #region ValidateEfControllerStep — Properties and Construction
-
- [Fact]
- public void ValidateEfControllerStep_IsScaffoldStep_Net10()
- {
- Assert.True(typeof(ValidateEfControllerStep).IsAssignableTo(typeof(ScaffoldStep)));
- }
-
- [Fact]
- public void ValidateEfControllerStep_HasProjectProperty_Net10()
- {
- Assert.NotNull(typeof(ValidateEfControllerStep).GetProperty("Project"));
- }
-
- [Fact]
- public void ValidateEfControllerStep_HasPrereleaseProperty_Net10()
- {
- Assert.NotNull(typeof(ValidateEfControllerStep).GetProperty("Prerelease"));
- }
-
- [Fact]
- public void ValidateEfControllerStep_HasDatabaseProviderProperty_Net10()
- {
- Assert.NotNull(typeof(ValidateEfControllerStep).GetProperty("DatabaseProvider"));
- }
-
- [Fact]
- public void ValidateEfControllerStep_HasDataContextProperty_Net10()
- {
- Assert.NotNull(typeof(ValidateEfControllerStep).GetProperty("DataContext"));
- }
-
- [Fact]
- public void ValidateEfControllerStep_HasModelProperty_Net10()
- {
- Assert.NotNull(typeof(ValidateEfControllerStep).GetProperty("Model"));
- }
-
- [Fact]
- public void ValidateEfControllerStep_HasControllerNameProperty_Net10()
- {
- Assert.NotNull(typeof(ValidateEfControllerStep).GetProperty("ControllerName"));
- }
-
- [Fact]
- public void ValidateEfControllerStep_HasControllerTypeProperty_Net10()
- {
- Assert.NotNull(typeof(ValidateEfControllerStep).GetProperty("ControllerType"));
- }
-
- [Fact]
- public void ValidateEfControllerStep_Has7Properties_Net10()
- {
- // Project, Prerelease, DatabaseProvider, DataContext, Model, ControllerName, ControllerType
- var props = typeof(ValidateEfControllerStep).GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
- Assert.Equal(7, props.Length);
- }
-
- [Fact]
- public void ValidateEfControllerStep_Constructor_RequiresFileSystem_Net10()
- {
- var ctor = typeof(ValidateEfControllerStep).GetConstructors().First();
- var parameters = ctor.GetParameters();
- Assert.Contains(parameters, p => p.ParameterType == typeof(IFileSystem));
- }
-
- [Fact]
- public void ValidateEfControllerStep_Constructor_RequiresLogger_Net10()
- {
- var ctor = typeof(ValidateEfControllerStep).GetConstructors().First();
- var parameters = ctor.GetParameters();
- Assert.Contains(parameters, p => p.ParameterType == typeof(ILogger));
- }
-
- [Fact]
- public void ValidateEfControllerStep_Constructor_RequiresTelemetryService_Net10()
- {
- var ctor = typeof(ValidateEfControllerStep).GetConstructors().First();
- var parameters = ctor.GetParameters();
- Assert.Contains(parameters, p => p.ParameterType == typeof(ITelemetryService));
- }
-
- [Fact]
- public void ValidateEfControllerStep_Constructor_Has3Parameters_Net10()
- {
- var ctor = typeof(ValidateEfControllerStep).GetConstructors().First();
- Assert.Equal(3, ctor.GetParameters().Length);
- }
-
- #endregion
-
- #region ValidateEfControllerStep — Validation Logic
-
- [Fact]
- public async Task ValidateEfControllerStep_FailsWhenProjectMissing_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_FailsWhenProjectFileDoesNotExist_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_FailsWhenModelMissing_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = string.Empty,
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_FailsWhenControllerNameMissing_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = string.Empty,
- ControllerType = "API",
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_FailsWhenControllerTypeMissing_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = string.Empty,
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_FailsWhenDataContextMissing_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = string.Empty,
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_StepProperties_AreSetCorrectly_Net10()
- {
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer,
- Prerelease = true
- };
-
- Assert.Equal(_testProjectPath, step.Project);
- Assert.Equal("Product", step.Model);
- Assert.Equal("ProductsController", step.ControllerName);
- Assert.Equal("API", step.ControllerType);
- Assert.Equal("AppDbContext", step.DataContext);
- Assert.Equal(PackageConstants.EfConstants.SqlServer, step.DatabaseProvider);
- Assert.True(step.Prerelease);
- }
-
- #endregion
-
- #region Telemetry
-
- [Fact]
- public async Task TelemetryEventName_IsValidateEfControllerStepEvent_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext"
- };
-
- await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.Single(_testTelemetryService.TrackedEvents);
- Assert.Equal("ValidateEfControllerStepEvent", _testTelemetryService.TrackedEvents[0].EventName);
- }
-
- [Fact]
- public async Task TelemetryEvent_ContainsScaffolderNameProperty_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext"
- };
-
- await step.ExecuteAsync(_context, CancellationToken.None);
-
- var props = _testTelemetryService.TrackedEvents[0].Properties;
- Assert.True(props.ContainsKey("ScaffolderName"));
- Assert.Equal("API Controller with actions, using Entity Framework (CRUD)", props["ScaffolderName"]);
- }
-
- [Fact]
- public async Task TelemetryEvent_ContainsResultProperty_OnFailure_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext"
- };
-
- await step.ExecuteAsync(_context, CancellationToken.None);
-
- var props = _testTelemetryService.TrackedEvents[0].Properties;
- Assert.True(props.ContainsKey("Result"));
- Assert.Equal("Failure", props["Result"]);
- }
-
- [Fact]
- public async Task TelemetryEvent_SingleEventPerValidation_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = string.Empty,
- Model = string.Empty,
- ControllerName = string.Empty,
- ControllerType = string.Empty,
- DataContext = string.Empty
- };
-
- await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- #endregion
-
- #region EfControllerModel Properties
-
- [Fact]
- public void EfControllerModel_HasControllerTypeProperty_Net10()
- {
- Assert.NotNull(typeof(EfControllerModel).GetProperty("ControllerType"));
- }
-
- [Fact]
- public void EfControllerModel_HasControllerNameProperty_Net10()
- {
- Assert.NotNull(typeof(EfControllerModel).GetProperty("ControllerName"));
- }
-
- [Fact]
- public void EfControllerModel_HasControllerOutputPathProperty_Net10()
- {
- Assert.NotNull(typeof(EfControllerModel).GetProperty("ControllerOutputPath"));
- }
-
- [Fact]
- public void EfControllerModel_HasDbContextInfoProperty_Net10()
- {
- Assert.NotNull(typeof(EfControllerModel).GetProperty("DbContextInfo"));
- }
-
- [Fact]
- public void EfControllerModel_HasModelInfoProperty_Net10()
- {
- Assert.NotNull(typeof(EfControllerModel).GetProperty("ModelInfo"));
- }
-
- [Fact]
- public void EfControllerModel_HasProjectInfoProperty_Net10()
- {
- Assert.NotNull(typeof(EfControllerModel).GetProperty("ProjectInfo"));
- }
-
- [Fact]
- public void EfControllerModel_Has6Properties_Net10()
- {
- var props = typeof(EfControllerModel).GetProperties(BindingFlags.Public | BindingFlags.Instance);
- Assert.Equal(6, props.Length);
- }
-
- #endregion
-
- #region EfControllerSettings Properties
-
- [Fact]
- public void EfControllerSettings_HasControllerTypeProperty_Net10()
- {
- Assert.NotNull(typeof(EfControllerSettings).GetProperty("ControllerType"));
- }
-
- [Fact]
- public void EfControllerSettings_HasControllerNameProperty_Net10()
- {
- Assert.NotNull(typeof(EfControllerSettings).GetProperty("ControllerName"));
- }
-
- [Fact]
- public void EfControllerSettings_InheritsFromEfWithModelStepSettings_Net10()
- {
- Assert.True(typeof(EfControllerSettings).IsAssignableTo(typeof(EfWithModelStepSettings)));
- }
-
- [Fact]
- public void EfControllerSettings_HasProjectProperty_Net10()
- {
- Assert.NotNull(typeof(EfControllerSettings).GetProperty("Project"));
- }
-
- [Fact]
- public void EfControllerSettings_HasModelProperty_Net10()
- {
- Assert.NotNull(typeof(EfControllerSettings).GetProperty("Model"));
- }
-
- [Fact]
- public void EfControllerSettings_HasDataContextProperty_Net10()
- {
- Assert.NotNull(typeof(EfControllerSettings).GetProperty("DataContext"));
- }
-
- [Fact]
- public void EfControllerSettings_HasDatabaseProviderProperty_Net10()
- {
- Assert.NotNull(typeof(EfControllerSettings).GetProperty("DatabaseProvider"));
- }
-
- [Fact]
- public void EfControllerSettings_HasPrereleaseProperty_Net10()
- {
- Assert.NotNull(typeof(EfControllerSettings).GetProperty("Prerelease"));
- }
-
- #endregion
-
- #region EfWithModelStepSettings Properties
-
- [Fact]
- public void EfWithModelStepSettings_InheritsFromBaseSettings_Net10()
- {
- Assert.True(typeof(EfWithModelStepSettings).IsAssignableTo(typeof(BaseSettings)));
- }
-
- [Fact]
- public void EfWithModelStepSettings_HasDatabaseProviderProperty_Net10()
- {
- Assert.NotNull(typeof(EfWithModelStepSettings).GetProperty("DatabaseProvider"));
- }
-
- [Fact]
- public void EfWithModelStepSettings_HasDataContextProperty_Net10()
- {
- Assert.NotNull(typeof(EfWithModelStepSettings).GetProperty("DataContext"));
- }
-
- [Fact]
- public void EfWithModelStepSettings_HasModelProperty_Net10()
- {
- Assert.NotNull(typeof(EfWithModelStepSettings).GetProperty("Model"));
- }
-
- [Fact]
- public void EfWithModelStepSettings_HasPrereleaseProperty_Net10()
- {
- Assert.NotNull(typeof(EfWithModelStepSettings).GetProperty("Prerelease"));
- }
-
- #endregion
-
- #region BaseSettings Properties
-
- [Fact]
- public void BaseSettings_HasProjectProperty_Net10()
- {
- Assert.NotNull(typeof(BaseSettings).GetProperty("Project"));
- }
-
- [Fact]
- public void BaseSettings_IsInternal_Net10()
- {
- Assert.False(typeof(BaseSettings).IsPublic);
- }
-
- #endregion
-
- #region DbContextInfo Properties
-
- [Fact]
- public void DbContextInfo_HasDbContextClassNameProperty_Net10()
- {
- Assert.NotNull(typeof(DbContextInfo).GetProperty("DbContextClassName"));
- }
-
- [Fact]
- public void DbContextInfo_HasDbContextClassPathProperty_Net10()
- {
- Assert.NotNull(typeof(DbContextInfo).GetProperty("DbContextClassPath"));
- }
-
- [Fact]
- public void DbContextInfo_HasDbContextNamespaceProperty_Net10()
- {
- Assert.NotNull(typeof(DbContextInfo).GetProperty("DbContextNamespace"));
- }
-
- [Fact]
- public void DbContextInfo_HasDatabaseProviderProperty_Net10()
- {
- Assert.NotNull(typeof(DbContextInfo).GetProperty("DatabaseProvider"));
- }
-
- [Fact]
- public void DbContextInfo_HasEfScenarioProperty_Net10()
- {
- Assert.NotNull(typeof(DbContextInfo).GetProperty("EfScenario"));
- }
-
- [Fact]
- public void DbContextInfo_DefaultEfScenario_IsFalse_Net10()
- {
- var info = new DbContextInfo();
- Assert.False(info.EfScenario);
- }
-
- #endregion
-
- #region ModelInfo Properties
-
- [Fact]
- public void ModelInfo_HasModelTypeNameProperty_Net10()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("ModelTypeName"));
- }
-
- [Fact]
- public void ModelInfo_HasModelNamespaceProperty_Net10()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("ModelNamespace"));
- }
-
- [Fact]
- public void ModelInfo_HasModelFullNameProperty_Net10()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("ModelFullName"));
- }
-
- [Fact]
- public void ModelInfo_HasModelTypeNameCapitalizedProperty_Net10()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("ModelTypeNameCapitalized"));
- }
-
- [Fact]
- public void ModelInfo_HasModelTypePluralNameProperty_Net10()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("ModelTypePluralName"));
- }
-
- [Fact]
- public void ModelInfo_HasModelVariableProperty_Net10()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("ModelVariable"));
- }
-
- [Fact]
- public void ModelInfo_HasPrimaryKeyNameProperty_Net10()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("PrimaryKeyName"));
- }
-
- [Fact]
- public void ModelInfo_HasPrimaryKeyShortTypeNameProperty_Net10()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("PrimaryKeyShortTypeName"));
- }
-
- [Fact]
- public void ModelInfo_HasPrimaryKeyTypeNameProperty_Net10()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("PrimaryKeyTypeName"));
- }
-
- [Fact]
- public void ModelInfo_ComputedProperties_WorkCorrectly_Net10()
- {
- var modelInfo = new ModelInfo { ModelTypeName = "product" };
- Assert.Equal("Product", modelInfo.ModelTypeNameCapitalized);
- Assert.Equal("products", modelInfo.ModelTypePluralName);
- Assert.Equal("product", modelInfo.ModelVariable);
- }
-
- #endregion
-
- #region PackageConstants — EF
-
- [Fact]
- public void PackageConstants_SqlServer_HasCorrectKey_Net10()
- {
- Assert.Equal("sqlserver-efcore", PackageConstants.EfConstants.SqlServer);
- }
-
- [Fact]
- public void PackageConstants_SQLite_HasCorrectKey_Net10()
- {
- Assert.Equal("sqlite-efcore", PackageConstants.EfConstants.SQLite);
- }
-
- [Fact]
- public void PackageConstants_CosmosDb_HasCorrectKey_Net10()
- {
- Assert.Equal("cosmos-efcore", PackageConstants.EfConstants.CosmosDb);
- }
-
- [Fact]
- public void PackageConstants_Postgres_HasCorrectKey_Net10()
- {
- Assert.Equal("npgsql-efcore", PackageConstants.EfConstants.Postgres);
- }
-
- [Fact]
- public void PackageConstants_EfCorePackage_HasCorrectName_Net10()
- {
- Assert.Equal("Microsoft.EntityFrameworkCore", PackageConstants.EfConstants.EfCorePackage.Name);
- }
-
- [Fact]
- public void PackageConstants_EfCorePackage_RequiresVersion_Net10()
- {
- Assert.True(PackageConstants.EfConstants.EfCorePackage.IsVersionRequired);
- }
-
- [Fact]
- public void PackageConstants_EfCoreToolsPackage_HasCorrectName_Net10()
- {
- Assert.Equal("Microsoft.EntityFrameworkCore.Tools", PackageConstants.EfConstants.EfCoreToolsPackage.Name);
- }
-
- [Fact]
- public void PackageConstants_EfCoreToolsPackage_RequiresVersion_Net10()
- {
- Assert.True(PackageConstants.EfConstants.EfCoreToolsPackage.IsVersionRequired);
- }
-
- [Fact]
- public void PackageConstants_SqlServerPackage_HasCorrectName_Net10()
- {
- Assert.Equal("Microsoft.EntityFrameworkCore.SqlServer", PackageConstants.EfConstants.SqlServerPackage.Name);
- }
-
- [Fact]
- public void PackageConstants_SqlitePackage_HasCorrectName_Net10()
- {
- Assert.Equal("Microsoft.EntityFrameworkCore.Sqlite", PackageConstants.EfConstants.SqlitePackage.Name);
- }
-
- [Fact]
- public void PackageConstants_CosmosPackage_HasCorrectName_Net10()
- {
- Assert.Equal("Microsoft.EntityFrameworkCore.Cosmos", PackageConstants.EfConstants.CosmosPackage.Name);
- }
-
- [Fact]
- public void PackageConstants_PostgresPackage_HasCorrectName_Net10()
- {
- Assert.Equal("Npgsql.EntityFrameworkCore.PostgreSQL", PackageConstants.EfConstants.PostgresPackage.Name);
- }
-
- [Fact]
- public void PackageConstants_EfPackagesDict_Contains4Providers_Net10()
- {
- Assert.Equal(4, PackageConstants.EfConstants.EfPackagesDict.Count);
- }
-
- [Fact]
- public void PackageConstants_EfPackagesDict_ContainsSqlServer_Net10()
- {
- Assert.True(PackageConstants.EfConstants.EfPackagesDict.ContainsKey(PackageConstants.EfConstants.SqlServer));
- }
-
- [Fact]
- public void PackageConstants_EfPackagesDict_ContainsSQLite_Net10()
- {
- Assert.True(PackageConstants.EfConstants.EfPackagesDict.ContainsKey(PackageConstants.EfConstants.SQLite));
- }
-
- [Fact]
- public void PackageConstants_EfPackagesDict_ContainsCosmosDb_Net10()
- {
- Assert.True(PackageConstants.EfConstants.EfPackagesDict.ContainsKey(PackageConstants.EfConstants.CosmosDb));
- }
-
- [Fact]
- public void PackageConstants_EfPackagesDict_ContainsPostgres_Net10()
- {
- Assert.True(PackageConstants.EfConstants.EfPackagesDict.ContainsKey(PackageConstants.EfConstants.Postgres));
- }
-
- [Fact]
- public void PackageConstants_ConnectionStringVariableName_IsCorrect_Net10()
- {
- Assert.Equal("connectionString", PackageConstants.EfConstants.ConnectionStringVariableName);
- }
-
- #endregion
-
- #region UseDatabaseMethods
-
- [Fact]
- public void UseDatabaseMethods_SqlServer_UseSqlServer_Net10()
- {
- Assert.True(PackageConstants.EfConstants.UseDatabaseMethods.ContainsKey(PackageConstants.EfConstants.SqlServer));
- Assert.Equal("UseSqlServer", PackageConstants.EfConstants.UseDatabaseMethods[PackageConstants.EfConstants.SqlServer]);
- }
-
- [Fact]
- public void UseDatabaseMethods_SQLite_UseSqlite_Net10()
- {
- Assert.True(PackageConstants.EfConstants.UseDatabaseMethods.ContainsKey(PackageConstants.EfConstants.SQLite));
- Assert.Equal("UseSqlite", PackageConstants.EfConstants.UseDatabaseMethods[PackageConstants.EfConstants.SQLite]);
- }
-
- [Fact]
- public void UseDatabaseMethods_Postgres_UseNpgsql_Net10()
- {
- Assert.True(PackageConstants.EfConstants.UseDatabaseMethods.ContainsKey(PackageConstants.EfConstants.Postgres));
- Assert.Equal("UseNpgsql", PackageConstants.EfConstants.UseDatabaseMethods[PackageConstants.EfConstants.Postgres]);
- }
-
- [Fact]
- public void UseDatabaseMethods_CosmosDb_UseCosmos_Net10()
- {
- Assert.True(PackageConstants.EfConstants.UseDatabaseMethods.ContainsKey(PackageConstants.EfConstants.CosmosDb));
- Assert.Equal("UseCosmos", PackageConstants.EfConstants.UseDatabaseMethods[PackageConstants.EfConstants.CosmosDb]);
- }
-
- #endregion
-
- #region Template Folder Verification — Net10 (.tt text template format)
-
- [Fact]
- public void Net10TemplateFolder_ContainsApiEfControllerTtTemplate_Net10()
- {
- var assembly = typeof(EfControllerHelper).Assembly;
- string basePath = Path.GetDirectoryName(assembly.Location)!;
- string templatePath = Path.Combine(basePath, "Templates", TargetFramework, "EfController", "ApiEfController.tt");
-
- if (File.Exists(templatePath))
- {
- string content = File.ReadAllText(templatePath);
- Assert.NotEmpty(content);
- }
- else
- {
- // .tt templates compiled into the assembly; no physical .tt file expected at runtime
- Assert.True(true, ".tt template compiled into assembly at build time");
- }
- }
-
- [Fact]
- public void Net10TemplateFolder_ContainsMvcEfControllerTtTemplate_Net10()
- {
- var assembly = typeof(EfControllerHelper).Assembly;
- string basePath = Path.GetDirectoryName(assembly.Location)!;
- string templatePath = Path.Combine(basePath, "Templates", TargetFramework, "EfController", "MvcEfController.tt");
-
- if (File.Exists(templatePath))
- {
- string content = File.ReadAllText(templatePath);
- Assert.NotEmpty(content);
- }
- else
- {
- Assert.True(true, ".tt template compiled into assembly at build time");
- }
- }
-
- [Fact]
- public void Net10TemplateFolder_DoesNotUseLegacyCshtmlTemplates_Net10()
- {
- // Net10 EfController folder should NOT have .cshtml templates (those are only in net8.0)
- var assembly = typeof(EfControllerHelper).Assembly;
- string basePath = Path.GetDirectoryName(assembly.Location)!;
- string efControllerDir = Path.Combine(basePath, "Templates", TargetFramework, "EfController");
-
- if (Directory.Exists(efControllerDir))
- {
- var cshtmlFiles = Directory.GetFiles(efControllerDir, "*.cshtml");
- Assert.Empty(cshtmlFiles);
- }
- else
- {
- // Templates compiled into assembly; no physical folder expected
- Assert.True(true);
- }
- }
-
- #endregion
-
- #region Net10 Template Type Resolution — Templates.net10.EfController namespace (canonical)
-
- [Fact]
- public void Net10TemplateTypes_AreCanonicalCompiledTypes_Net10()
- {
- // Net10 .cs files are explicitly re-included via Compile Update in the csproj,
- // making Templates.net10.EfController the canonical compiled template types.
- var assembly = typeof(EfControllerHelper).Assembly;
- var allTypes = assembly.GetTypes();
- var net10EfControllerTypes = allTypes.Where(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.EfController")).ToList();
-
- Assert.True(net10EfControllerTypes.Count > 0, "Expected net10 EfController template types in Templates.net10.EfController namespace");
- }
-
- [Fact]
- public void Net10TemplateTypes_ApiEfController_Exists_Net10()
- {
- var assembly = typeof(EfControllerHelper).Assembly;
- var allTypes = assembly.GetTypes();
- var apiType = allTypes.FirstOrDefault(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.EfController") &&
- t.Name.Equals("ApiEfController", StringComparison.OrdinalIgnoreCase));
-
- Assert.NotNull(apiType);
- }
-
- [Fact]
- public void Net10TemplateTypes_MvcEfController_Exists_Net10()
- {
- var assembly = typeof(EfControllerHelper).Assembly;
- var allTypes = assembly.GetTypes();
- var mvcType = allTypes.FirstOrDefault(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.EfController") &&
- t.Name.Equals("MvcEfController", StringComparison.OrdinalIgnoreCase));
-
- Assert.NotNull(mvcType);
- }
-
- [Fact]
- public void Net10TemplateTypes_ApiEfController_InCorrectNamespace_Net10()
- {
- // GetCrudControllerType maps "ApiEfController.tt" → typeof(Templates.net10.EfController.ApiEfController)
- var assembly = typeof(EfControllerHelper).Assembly;
- var apiType = assembly.GetTypes().FirstOrDefault(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.EfController") &&
- t.Name.Equals("ApiEfController", StringComparison.OrdinalIgnoreCase));
- Assert.NotNull(apiType);
- Assert.Contains("Templates.net10.EfController", apiType!.FullName);
- }
-
- [Fact]
- public void Net10TemplateTypes_MvcEfController_InCorrectNamespace_Net10()
- {
- // GetCrudControllerType maps "MvcEfController.tt" → typeof(Templates.net10.EfController.MvcEfController)
- var assembly = typeof(EfControllerHelper).Assembly;
- var mvcType = assembly.GetTypes().FirstOrDefault(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.EfController") &&
- t.Name.Equals("MvcEfController", StringComparison.OrdinalIgnoreCase));
- Assert.NotNull(mvcType);
- Assert.Contains("Templates.net10.EfController", mvcType!.FullName);
- }
-
- #endregion
-
- #region EfControllerHelper — GetCrudControllerType uses net10 types
-
- [Fact]
- public void EfControllerHelper_TemplateTypes_AreResolvableFromAssembly_Net10()
- {
- var assembly = typeof(EfControllerHelper).Assembly;
- var allTypes = assembly.GetTypes();
- var net10EfControllerTypes = allTypes.Where(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.EfController")).ToList();
-
- Assert.True(net10EfControllerTypes.Count > 0, "Expected net10 EfController template types in assembly");
- }
-
- [Fact]
- public void EfControllerHelper_ThrowsWhenProjectInfoNull_Net10()
- {
- var model = new EfControllerModel
- {
- ControllerType = "API",
- ControllerName = "ProductsController",
- ControllerOutputPath = "Controllers",
- DbContextInfo = new DbContextInfo { DbContextClassName = "AppDbContext", EfScenario = true },
- ModelInfo = new ModelInfo { ModelTypeName = "Product" },
- ProjectInfo = new ProjectInfo(null)
- };
-
- Assert.Throws(() =>
- EfControllerHelper.GetEfControllerTemplatingProperty(model));
- }
-
- #endregion
-
- #region Code Modification Configs
-
- [Fact]
- public void Net10CodeModificationConfig_EfControllerChanges_Exists_Net10()
- {
- // The code currently hardcodes net11.0 for the targetFrameworkFolder
- var assembly = typeof(EfControllerHelper).Assembly;
- string basePath = Path.GetDirectoryName(assembly.Location)!;
- string configPath = Path.Combine(basePath, "Templates", "net11.0", "CodeModificationConfigs", "efControllerChanges.json");
-
- if (File.Exists(configPath))
- {
- string content = File.ReadAllText(configPath);
- Assert.Contains("Program.cs", content);
- }
- else
- {
- Assert.True(true, "Config file expected embedded in assembly");
- }
- }
-
- #endregion
-
- #region Pipeline Step Sequence
-
- [Fact]
- public void ApiControllerCrudPipeline_DefinesCorrectStepSequence_Net10()
- {
- // API Controller CRUD pipeline: ValidateEfControllerStep → WithEfControllerAddPackagesStep → WithDbContextStep
- // → WithAspNetConnectionStringStep → WithEfControllerTextTemplatingStep → WithEfControllerCodeChangeStep
- Assert.NotNull(typeof(ValidateEfControllerStep));
- Assert.True(typeof(ValidateEfControllerStep).IsClass);
+ protected override string TargetFramework => "net10.0";
+ protected override string TestClassName => nameof(ApiControllerNet10IntegrationTests);
+
+ [Fact]
+ public async Task Scaffold_ApiControllerCrud_Net10_CliInvocation()
+ {
+ // Arrange — set up project with Program.cs and a model class
+ File.WriteAllText(_testProjectPath, ProjectContent);
+ File.WriteAllText(Path.Combine(_testProjectDir, "Program.cs"), ScaffoldCliHelper.GetMinimalProgramCs());
+ var modelsDir = Path.Combine(_testProjectDir, "Models");
+ Directory.CreateDirectory(modelsDir);
+ File.WriteAllText(Path.Combine(modelsDir, "TestModel.cs"), ScaffoldCliHelper.GetModelClassContent("TestProject", "TestModel"));
+
+ // Verify project builds before scaffolding
+ var (beforeExitCode, _, beforeError) = await RunBuildAsync(_testProjectDir);
+ Assert.True(beforeExitCode == 0, $"Project should build before scaffolding. Error: {beforeError}");
+
+ // Act — invoke CLI: dotnet scaffold aspnet apicontroller-crud
+ var (cliExitCode, cliOutput, cliError) = await ScaffoldCliHelper.RunScaffoldAsync(
+ TargetFramework,
+ "apicontroller-crud",
+ "--project", _testProjectPath,
+ "--model", "TestModel",
+ "--controller", "TestApiController",
+ "--dataContext", "TestDbContext",
+ "--dbProvider", "sqlite-efcore");
+ Assert.True(cliExitCode == 0, $"CLI scaffold should succeed.\nOutput: {cliOutput}\nError: {cliError}");
+
+ // Assert — expected files were created
+ Assert.True(File.Exists(Path.Combine(_testProjectDir, "Controllers", "TestApiController.cs")),
+ "Controller file 'Controllers/TestApiController.cs' should be created.");
+ Assert.True(File.Exists(Path.Combine(_testProjectDir, "Data", "TestDbContext.cs")),
+ "DbContext file 'Data/TestDbContext.cs' should be created.");
+ var programContent = File.ReadAllText(Path.Combine(_testProjectDir, "Program.cs"));
+ Assert.Contains("TestDbContext", programContent);
+
+ // Assert — no NuGet errors and project builds after scaffolding
+ Assert.False(cliOutput.Contains("error: NU"),
+ $"Scaffolding should not produce NuGet errors for {TargetFramework}.\nOutput: {cliOutput}");
+ var (afterExitCode, _, afterError) = await RunBuildAsync(_testProjectDir);
+ Assert.True(afterExitCode == 0, $"Project should still build after scaffolding. Error: {afterError}");
}
-
- [Fact]
- public void MvcControllerCrudPipeline_HasAdditionalMvcViewsStep_Net10()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions);
- var method = extensionType.GetMethod("WithMvcViewsStep", BindingFlags.Public | BindingFlags.Static);
- Assert.NotNull(method);
- }
-
- [Fact]
- public void EfControllerPipeline_AllKeyStepsInheritFromScaffoldStep_Net10()
- {
- Assert.True(typeof(ValidateEfControllerStep).IsAssignableTo(typeof(ScaffoldStep)));
- }
-
- [Fact]
- public void EfControllerPipeline_AllKeyStepsAreInScaffoldStepsNamespace_Net10()
- {
- string expectedNs = "Microsoft.DotNet.Tools.Scaffold.AspNet.ScaffoldSteps";
- Assert.Equal(expectedNs, typeof(ValidateEfControllerStep).Namespace);
- }
-
- #endregion
-
- #region Builder Extensions
-
- [Fact]
- public void EfControllerBuilderExtensions_WithEfControllerTextTemplatingStep_Exists_Net10()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions);
- var method = extensionType.GetMethod("WithEfControllerTextTemplatingStep", BindingFlags.Public | BindingFlags.Static);
- Assert.NotNull(method);
- }
-
- [Fact]
- public void EfControllerBuilderExtensions_WithEfControllerAddPackagesStep_Exists_Net10()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions);
- var method = extensionType.GetMethod("WithEfControllerAddPackagesStep", BindingFlags.Public | BindingFlags.Static);
- Assert.NotNull(method);
- }
-
- [Fact]
- public void EfControllerBuilderExtensions_WithEfControllerCodeChangeStep_Exists_Net10()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions);
- var method = extensionType.GetMethod("WithEfControllerCodeChangeStep", BindingFlags.Public | BindingFlags.Static);
- Assert.NotNull(method);
- }
-
- [Fact]
- public void EfControllerBuilderExtensions_WithMvcViewsStep_Exists_Net10()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions);
- var method = extensionType.GetMethod("WithMvcViewsStep", BindingFlags.Public | BindingFlags.Static);
- Assert.NotNull(method);
- }
-
- [Fact]
- public void EfControllerBuilderExtensions_Has4ExtensionMethods_Net10()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions);
- var methods = extensionType.GetMethods(BindingFlags.Public | BindingFlags.Static)
- .Where(m => m.GetParameters().Any(p => p.ParameterType == typeof(IScaffoldBuilder)))
- .ToList();
- Assert.Equal(4, methods.Count);
- }
-
- [Fact]
- public void EfControllerBuilderExtensions_AllMethodsReturnIScaffoldBuilder_Net10()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions);
- var methods = extensionType.GetMethods(BindingFlags.Public | BindingFlags.Static)
- .Where(m => m.GetParameters().Any(p => p.ParameterType == typeof(IScaffoldBuilder)))
- .ToList();
-
- foreach (var method in methods)
- {
- Assert.Equal(typeof(IScaffoldBuilder), method.ReturnType);
- }
- }
-
- #endregion
-
- #region TFM Availability
-
- [Fact]
- public void ApiControllerCrud_IsAvailableForNet10_Net10()
- {
- // API category is available for all TFMs including Net10
- Assert.Equal("API", AspnetStrings.Catagories.API);
- }
-
- [Fact]
- public void MvcControllerCrud_IsAvailableForNet10_Net10()
- {
- // MVC category is available for all TFMs including Net10
- Assert.Equal("MVC", AspnetStrings.Catagories.MVC);
- }
-
- [Fact]
- public void CommandInfoExtensions_IsCommandAnAspNetCommand_Exists_Net10()
- {
- var method = typeof(CommandInfoExtensions).GetMethod("IsCommandAnAspNetCommand");
- Assert.NotNull(method);
- }
-
- #endregion
-
- #region Cancellation Support
-
- [Fact]
- public async Task ValidateEfControllerStep_AcceptsCancellationToken_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext"
- };
-
- using var cts = new CancellationTokenSource();
- bool result = await step.ExecuteAsync(_context, cts.Token);
-
- Assert.False(result);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_ExecuteAsync_IsInherited_Net10()
- {
- var method = typeof(ValidateEfControllerStep).GetMethod("ExecuteAsync", new[] { typeof(ScaffolderContext), typeof(CancellationToken) });
- Assert.NotNull(method);
- Assert.True(method!.IsVirtual);
- }
-
- #endregion
-
- #region Scaffolder Registration Constants
-
- [Fact]
- public void ApiControllerCrud_UsesCorrectName_Net10()
- {
- Assert.Equal("apicontroller-crud", AspnetStrings.Api.ApiControllerCrud);
- }
-
- [Fact]
- public void ApiControllerCrud_UsesCorrectDisplayName_Net10()
- {
- Assert.Equal("API Controller with actions, using Entity Framework (CRUD)", AspnetStrings.Api.ApiControllerCrudDisplayName);
- }
-
- [Fact]
- public void ApiControllerCrud_UsesCorrectCategory_Net10()
- {
- Assert.Equal("API", AspnetStrings.Catagories.API);
- }
-
- [Fact]
- public void ApiControllerCrud_UsesCorrectDescription_Net10()
- {
- Assert.Equal("Create an API controller with REST actions to create, read, update, delete, and list entities", AspnetStrings.Api.ApiControllerCrudDescription);
- }
-
- [Fact]
- public void ApiControllerCrud_Has2Examples_Net10()
- {
- Assert.NotEmpty(AspnetStrings.Api.ApiControllerCrudExample1);
- Assert.NotEmpty(AspnetStrings.Api.ApiControllerCrudExample2);
- Assert.NotEmpty(AspnetStrings.Api.ApiControllerCrudExample1Description);
- Assert.NotEmpty(AspnetStrings.Api.ApiControllerCrudExample2Description);
- }
-
- [Fact]
- public void MvcControllerCrud_Has2Examples_Net10()
- {
- Assert.NotEmpty(AspnetStrings.MVC.ControllerCrudExample1);
- Assert.NotEmpty(AspnetStrings.MVC.ControllerCrudExample2);
- Assert.NotEmpty(AspnetStrings.MVC.ControllerCrudExample1Description);
- Assert.NotEmpty(AspnetStrings.MVC.ControllerCrudExample2Description);
- }
-
- #endregion
-
- #region Scaffolding Context Properties
-
- [Fact]
- public void ScaffolderContext_CanStoreEfControllerModel_Net10()
- {
- var model = new EfControllerModel
- {
- ControllerType = "API",
- ControllerName = "ProductsController",
- ControllerOutputPath = Path.Combine(_testProjectDir, "Controllers"),
- DbContextInfo = new DbContextInfo { DbContextClassName = "AppDbContext", EfScenario = true },
- ModelInfo = new ModelInfo { ModelTypeName = "Product" },
- ProjectInfo = new ProjectInfo(_testProjectPath)
- };
-
- _context.Properties.Add(nameof(EfControllerModel), model);
-
- Assert.True(_context.Properties.ContainsKey(nameof(EfControllerModel)));
- var retrieved = _context.Properties[nameof(EfControllerModel)] as EfControllerModel;
- Assert.NotNull(retrieved);
- Assert.Equal("API", retrieved!.ControllerType);
- Assert.Equal("ProductsController", retrieved.ControllerName);
- Assert.Equal("Product", retrieved.ModelInfo.ModelTypeName);
- Assert.True(retrieved.DbContextInfo.EfScenario);
- }
-
- [Fact]
- public void ScaffolderContext_CanStoreEfControllerSettings_Net10()
- {
- var settings = new EfControllerSettings
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer,
- Prerelease = false
- };
-
- _context.Properties.Add(nameof(EfControllerSettings), settings);
-
- Assert.True(_context.Properties.ContainsKey(nameof(EfControllerSettings)));
- var retrieved = _context.Properties[nameof(EfControllerSettings)] as EfControllerSettings;
- Assert.NotNull(retrieved);
- Assert.Equal(_testProjectPath, retrieved!.Project);
- Assert.Equal("API", retrieved.ControllerType);
- Assert.Equal("Product", retrieved.Model);
- }
-
- [Fact]
- public void ScaffolderContext_CanStoreCodeModifierProperties_Net10()
- {
- var codeModifierProperties = new Dictionary
- {
- { "DbContextName", "AppDbContext" },
- { "ConnectionStringName", "DefaultConnection" }
- };
-
- _context.Properties.Add(Scaffolding.Internal.Constants.StepConstants.CodeModifierProperties, codeModifierProperties);
-
- Assert.True(_context.Properties.ContainsKey(Scaffolding.Internal.Constants.StepConstants.CodeModifierProperties));
- var retrieved = _context.Properties[Scaffolding.Internal.Constants.StepConstants.CodeModifierProperties] as Dictionary;
- Assert.NotNull(retrieved);
- Assert.Equal(2, retrieved!.Count);
- }
-
- #endregion
-
- #region ControllerOutputPath Constant
-
- [Fact]
- public void ControllerCommandOutput_IsControllers_Net10()
- {
- Assert.Equal("Controllers", AspNetConstants.DotnetCommands.ControllerCommandOutput);
- }
-
- #endregion
-
- #region NewDbContext Constant
-
- [Fact]
- public void NewDbContext_HasCorrectValue_Net10()
- {
- Assert.Equal("NewDbContext", AspNetConstants.NewDbContext);
- }
-
- #endregion
-
- #region File Extensions
-
- [Fact]
- public void CSharpExtension_IsCorrect_Net10()
- {
- Assert.Equal(".cs", AspNetConstants.CSharpExtension);
- }
-
- #endregion
-
- #region Validation Combination Tests
-
- [Fact]
- public async Task ValidateEfControllerStep_NullProject_FailsValidation_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = null,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext"
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_NullModel_FailsValidation_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = null,
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext"
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_NullControllerName_FailsValidation_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = null,
- ControllerType = "API",
- DataContext = "AppDbContext"
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_NullControllerType_FailsValidation_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = null,
- DataContext = "AppDbContext"
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_NullDataContext_FailsValidation_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = null
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_AllFieldsEmpty_FailsValidation_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = string.Empty,
- Model = string.Empty,
- ControllerName = string.Empty,
- ControllerType = string.Empty,
- DataContext = string.Empty
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- #endregion
-
- #region Regression Guards
-
- [Fact]
- public void EfControllerModel_IsInModelsNamespace_Net10()
- {
- Assert.Equal("Microsoft.DotNet.Tools.Scaffold.AspNet.Models", typeof(EfControllerModel).Namespace);
- }
-
- [Fact]
- public void EfControllerSettings_IsInSettingsNamespace_Net10()
- {
- Assert.Equal("Microsoft.DotNet.Tools.Scaffold.AspNet.ScaffoldSteps.Settings", typeof(EfControllerSettings).Namespace);
- }
-
- [Fact]
- public void EfControllerHelper_IsInHelpersNamespace_Net10()
- {
- Assert.Equal("Microsoft.DotNet.Tools.Scaffold.AspNet.Helpers", typeof(EfControllerHelper).Namespace);
- }
-
- [Fact]
- public void ValidateEfControllerStep_IsInternal_Net10()
- {
- Assert.False(typeof(ValidateEfControllerStep).IsPublic);
- }
-
- [Fact]
- public void EfControllerModel_IsInternal_Net10()
- {
- Assert.False(typeof(EfControllerModel).IsPublic);
- }
-
- [Fact]
- public void EfControllerSettings_IsInternal_Net10()
- {
- Assert.False(typeof(EfControllerSettings).IsPublic);
- }
-
- [Fact]
- public void EfControllerScaffolderBuilderExtensions_IsInternal_Net10()
- {
- Assert.False(typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions).IsPublic);
- }
-
- [Fact]
- public void EfControllerHelper_IsInternal_Net10()
- {
- Assert.False(typeof(EfControllerHelper).IsPublic);
- }
-
- [Fact]
- public void EfControllerHelper_IsStatic_Net10()
- {
- Assert.True(typeof(EfControllerHelper).IsAbstract && typeof(EfControllerHelper).IsSealed);
- }
-
- [Fact]
- public void DbContextInfo_IsInternal_Net10()
- {
- Assert.False(typeof(DbContextInfo).IsPublic);
- }
-
- [Fact]
- public void ModelInfo_IsInternal_Net10()
- {
- Assert.False(typeof(ModelInfo).IsPublic);
- }
-
- #endregion
-
- #region API Controller Scaffolder — Non-CRUD Strings
-
- [Fact]
- public void ApiControllerNonCrud_Name_IsApiController_Net10()
- {
- Assert.Equal("apicontroller", AspnetStrings.Api.ApiController);
- }
-
- [Fact]
- public void ApiControllerNonCrud_DisplayName_Net10()
- {
- Assert.Equal("API Controller", AspnetStrings.Api.ApiControllerDisplayName);
- }
-
- [Fact]
- public void MvcControllerNonCrud_Name_IsMvcController_Net10()
- {
- Assert.Equal("mvccontroller", AspnetStrings.MVC.Controller);
- }
-
- [Fact]
- public void MvcControllerNonCrud_DisplayName_Net10()
- {
- Assert.Equal("MVC Controller", AspnetStrings.MVC.DisplayName);
- }
-
- #endregion
-
- #region ControllerType Values
-
- [Fact]
- public void ControllerType_APIValue_MatchesCategoryName_Net10()
- {
- Assert.Equal("API", AspnetStrings.Catagories.API);
- }
-
- [Fact]
- public void ControllerType_MVCValue_MatchesCategoryName_Net10()
- {
- Assert.Equal("MVC", AspnetStrings.Catagories.MVC);
- }
-
- #endregion
-
- #region TestTelemetryService Helper
-
- private class TestTelemetryService : ITelemetryService
- {
- public List<(string EventName, IReadOnlyDictionary Properties, IReadOnlyDictionary Measurements)> TrackedEvents { get; } = new();
-
- public void TrackEvent(string eventName, IReadOnlyDictionary properties, IReadOnlyDictionary measurements)
- {
- TrackedEvents.Add((eventName, properties, measurements));
- }
-
- public void Flush()
- {
- }
- }
-
- #endregion
}
diff --git a/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/ApiControllerNet11IntegrationTests.cs b/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/ApiControllerNet11IntegrationTests.cs
index ca25277b4..a8a4c4197 100644
--- a/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/ApiControllerNet11IntegrationTests.cs
+++ b/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/ApiControllerNet11IntegrationTests.cs
@@ -1,1774 +1,64 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System;
-using System.Collections.Generic;
using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Threading;
using System.Threading.Tasks;
-using Microsoft.DotNet.Scaffolding.Core.Builder;
-using Microsoft.DotNet.Scaffolding.Core.ComponentModel;
-using Microsoft.DotNet.Scaffolding.Core.Scaffolders;
-using Microsoft.DotNet.Scaffolding.Core.Steps;
-using Microsoft.DotNet.Scaffolding.Internal.Services;
-using Microsoft.DotNet.Scaffolding.Internal.Telemetry;
-using Microsoft.DotNet.Scaffolding.TextTemplating;
-using Microsoft.DotNet.Tools.Scaffold.AspNet;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.Commands;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.Common;
-using AspNetConstants = Microsoft.DotNet.Tools.Scaffold.AspNet.Common.Constants;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.Helpers;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.Models;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.ScaffoldSteps;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.ScaffoldSteps.Settings;
-using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Logging.Abstractions;
-using Moq;
+using Microsoft.DotNet.Tools.Scaffold.Tests.Helpers;
using Xunit;
namespace Microsoft.DotNet.Tools.Scaffold.Tests.AspNet.Integration.API;
-///
-/// Integration tests for the API Controller CRUD (apicontroller-crud) scaffolder targeting .NET 11.
-/// Validates scaffolder definition constants, ValidateEfControllerStep validation logic,
-/// EfControllerModel/EfControllerSettings/EfWithModelStepSettings/BaseSettings properties,
-/// EfControllerHelper template resolution, template folder verification, code modification configs,
-/// package constants, pipeline registration, step dependencies, telemetry tracking,
-/// TFM availability, builder extensions, and database provider support.
-/// .NET 11 EfController templates use .tt text template format (ApiEfController.tt, MvcEfController.tt).
-/// Unlike net9.0 and net10.0 (whose .cs files have explicit Compile Remove entries in the csproj),
-/// net11.0 EfController .cs files have NO Compile Remove — they compile normally as partial classes
-/// in the Templates.net10.EfController namespace (same as net10.0), contributing to the canonical
-/// compiled template types used by GetCrudControllerType at runtime.
-///
-public class ApiControllerNet11IntegrationTests : IDisposable
+public class ApiControllerNet11IntegrationTests : ApiControllerIntegrationTestsBase
{
- private const string TargetFramework = "net11.0";
- private readonly string _testDirectory;
- private readonly string _testProjectDir;
- private readonly string _testProjectPath;
- private readonly Mock _mockFileSystem;
- private readonly TestTelemetryService _testTelemetryService;
- private readonly Mock _mockScaffolder;
- private readonly ScaffolderContext _context;
-
- public ApiControllerNet11IntegrationTests()
- {
- _testDirectory = Path.Combine(Path.GetTempPath(), "ApiControllerNet11IntegrationTests", Guid.NewGuid().ToString());
- _testProjectDir = Path.Combine(_testDirectory, "TestProject");
- _testProjectPath = Path.Combine(_testProjectDir, "TestProject.csproj");
- Directory.CreateDirectory(_testProjectDir);
-
- _mockFileSystem = new Mock();
- _testTelemetryService = new TestTelemetryService();
- _mockScaffolder = new Mock();
- _mockScaffolder.Setup(s => s.DisplayName).Returns(AspnetStrings.Api.ApiControllerCrudDisplayName);
- _mockScaffolder.Setup(s => s.Name).Returns(AspnetStrings.Api.ApiControllerCrud);
- _context = new ScaffolderContext(_mockScaffolder.Object);
- }
-
- public void Dispose()
- {
- if (Directory.Exists(_testDirectory))
- {
- try { Directory.Delete(_testDirectory, recursive: true); }
- catch { /* best-effort cleanup */ }
- }
- }
-
- #region Constants & Scaffolder Definition — API Controller CRUD
-
- [Fact]
- public void ScaffolderName_IsApiControllerCrud_Net11()
- {
- Assert.Equal("apicontroller-crud", AspnetStrings.Api.ApiControllerCrud);
- }
-
- [Fact]
- public void ScaffolderDisplayName_IsApiControllerCrudDisplayName_Net11()
- {
- Assert.Equal("API Controller with actions, using Entity Framework (CRUD)", AspnetStrings.Api.ApiControllerCrudDisplayName);
- }
-
- [Fact]
- public void ScaffolderDescription_IsApiControllerCrudDescription_Net11()
- {
- Assert.Equal("Create an API controller with REST actions to create, read, update, delete, and list entities", AspnetStrings.Api.ApiControllerCrudDescription);
- }
-
- [Fact]
- public void ScaffolderCategory_IsAPI_Net11()
- {
- Assert.Equal("API", AspnetStrings.Catagories.API);
- }
-
- [Fact]
- public void ScaffolderExample1_ContainsApiControllerCrudCommand_Net11()
- {
- Assert.Contains("apicontroller-crud", AspnetStrings.Api.ApiControllerCrudExample1);
- }
-
- [Fact]
- public void ScaffolderExample1_ContainsRequiredOptions_Net11()
- {
- Assert.Contains("--project", AspnetStrings.Api.ApiControllerCrudExample1);
- Assert.Contains("--model", AspnetStrings.Api.ApiControllerCrudExample1);
- Assert.Contains("--controller-name", AspnetStrings.Api.ApiControllerCrudExample1);
- Assert.Contains("--data-context", AspnetStrings.Api.ApiControllerCrudExample1);
- Assert.Contains("--database-provider", AspnetStrings.Api.ApiControllerCrudExample1);
- }
-
- [Fact]
- public void ScaffolderExample2_ContainsApiControllerCrudCommand_Net11()
- {
- Assert.Contains("apicontroller-crud", AspnetStrings.Api.ApiControllerCrudExample2);
- }
-
- [Fact]
- public void ScaffolderExample2_ContainsPrerelease_Net11()
- {
- Assert.Contains("--prerelease", AspnetStrings.Api.ApiControllerCrudExample2);
- }
-
- [Fact]
- public void ScaffolderExample1Description_MentionsCrudOperations_Net11()
- {
- Assert.Contains("CRUD", AspnetStrings.Api.ApiControllerCrudExample1Description);
- }
-
- [Fact]
- public void ScaffolderExample2Description_MentionsPostgreSQL_Net11()
- {
- Assert.Contains("PostgreSQL", AspnetStrings.Api.ApiControllerCrudExample2Description);
- }
-
- #endregion
-
- #region Constants & Scaffolder Definition — MVC Controller CRUD
-
- [Fact]
- public void MVC_ScaffolderName_IsMvcControllerCrud_Net11()
- {
- Assert.Equal("mvccontroller-crud", AspnetStrings.MVC.ControllerCrud);
- }
-
- [Fact]
- public void MVC_ScaffolderDisplayName_IsMvcControllerCrudDisplayName_Net11()
- {
- Assert.Equal("MVC Controller with views, using Entity Framework (CRUD)", AspnetStrings.MVC.CrudDisplayName);
- }
-
- [Fact]
- public void MVC_ScaffolderDescription_IsMvcControllerCrudDescription_Net11()
- {
- Assert.Equal("Create a MVC controller with read/write actions and views using Entity Framework", AspnetStrings.MVC.CrudDescription);
- }
-
- [Fact]
- public void MVC_ScaffolderCategory_IsMVC_Net11()
- {
- Assert.Equal("MVC", AspnetStrings.Catagories.MVC);
- }
-
- [Fact]
- public void MVC_ScaffolderExample1_ContainsMvcControllerCrudCommand_Net11()
- {
- Assert.Contains("mvccontroller-crud", AspnetStrings.MVC.ControllerCrudExample1);
- }
-
- [Fact]
- public void MVC_ScaffolderExample1_ContainsViewsOption_Net11()
- {
- Assert.Contains("--views", AspnetStrings.MVC.ControllerCrudExample1);
- }
-
- #endregion
-
- #region CLI Options
-
- [Fact]
- public void CliOption_ProjectOption_IsCorrect_Net11()
- {
- Assert.Equal("--project", AspNetConstants.CliOptions.ProjectCliOption);
- }
-
- [Fact]
- public void CliOption_ModelOption_IsCorrect_Net11()
- {
- Assert.Equal("--model", AspNetConstants.CliOptions.ModelCliOption);
- }
-
- [Fact]
- public void CliOption_DataContextOption_IsCorrect_Net11()
- {
- Assert.Equal("--dataContext", AspNetConstants.CliOptions.DataContextOption);
- }
-
- [Fact]
- public void CliOption_DbProviderOption_IsCorrect_Net11()
- {
- Assert.Equal("--dbProvider", AspNetConstants.CliOptions.DbProviderOption);
- }
-
- [Fact]
- public void CliOption_ControllerNameOption_IsCorrect_Net11()
- {
- Assert.Equal("--controller", AspNetConstants.CliOptions.ControllerNameOption);
- }
-
- [Fact]
- public void CliOption_PrereleaseOption_IsCorrect_Net11()
- {
- Assert.Equal("--prerelease", AspNetConstants.CliOptions.PrereleaseCliOption);
- }
-
- [Fact]
- public void CliOption_ViewsOption_IsCorrect_Net11()
- {
- Assert.Equal("--views", AspNetConstants.CliOptions.ViewsOption);
- }
-
- #endregion
-
- #region AspNetOptions for EfController
-
- [Fact]
- public void AspNetOptions_HasModelNameProperty_Net11()
- {
- var prop = typeof(AspNetOptions).GetProperty("ModelName");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasControllerNameProperty_Net11()
- {
- var prop = typeof(AspNetOptions).GetProperty("ControllerName");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasDataContextClassRequiredProperty_Net11()
- {
- var prop = typeof(AspNetOptions).GetProperty("DataContextClassRequired");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasDatabaseProviderRequiredProperty_Net11()
- {
- var prop = typeof(AspNetOptions).GetProperty("DatabaseProviderRequired");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasPrereleaseProperty_Net11()
- {
- var prop = typeof(AspNetOptions).GetProperty("Prerelease");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasViewsProperty_Net11()
- {
- var prop = typeof(AspNetOptions).GetProperty("Views");
- Assert.NotNull(prop);
- }
-
- #endregion
-
- #region ValidateEfControllerStep — Properties and Construction
-
- [Fact]
- public void ValidateEfControllerStep_IsScaffoldStep_Net11()
- {
- Assert.True(typeof(ValidateEfControllerStep).IsAssignableTo(typeof(ScaffoldStep)));
- }
-
- [Fact]
- public void ValidateEfControllerStep_HasProjectProperty_Net11()
- {
- Assert.NotNull(typeof(ValidateEfControllerStep).GetProperty("Project"));
- }
-
- [Fact]
- public void ValidateEfControllerStep_HasPrereleaseProperty_Net11()
- {
- Assert.NotNull(typeof(ValidateEfControllerStep).GetProperty("Prerelease"));
- }
-
- [Fact]
- public void ValidateEfControllerStep_HasDatabaseProviderProperty_Net11()
- {
- Assert.NotNull(typeof(ValidateEfControllerStep).GetProperty("DatabaseProvider"));
- }
-
- [Fact]
- public void ValidateEfControllerStep_HasDataContextProperty_Net11()
- {
- Assert.NotNull(typeof(ValidateEfControllerStep).GetProperty("DataContext"));
- }
-
- [Fact]
- public void ValidateEfControllerStep_HasModelProperty_Net11()
- {
- Assert.NotNull(typeof(ValidateEfControllerStep).GetProperty("Model"));
- }
-
- [Fact]
- public void ValidateEfControllerStep_HasControllerNameProperty_Net11()
- {
- Assert.NotNull(typeof(ValidateEfControllerStep).GetProperty("ControllerName"));
- }
-
- [Fact]
- public void ValidateEfControllerStep_HasControllerTypeProperty_Net11()
- {
- Assert.NotNull(typeof(ValidateEfControllerStep).GetProperty("ControllerType"));
- }
-
- [Fact]
- public void ValidateEfControllerStep_Has7Properties_Net11()
- {
- // Project, Prerelease, DatabaseProvider, DataContext, Model, ControllerName, ControllerType
- var props = typeof(ValidateEfControllerStep).GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
- Assert.Equal(7, props.Length);
- }
-
- [Fact]
- public void ValidateEfControllerStep_Constructor_RequiresFileSystem_Net11()
- {
- var ctor = typeof(ValidateEfControllerStep).GetConstructors().First();
- var parameters = ctor.GetParameters();
- Assert.Contains(parameters, p => p.ParameterType == typeof(IFileSystem));
- }
-
- [Fact]
- public void ValidateEfControllerStep_Constructor_RequiresLogger_Net11()
- {
- var ctor = typeof(ValidateEfControllerStep).GetConstructors().First();
- var parameters = ctor.GetParameters();
- Assert.Contains(parameters, p => p.ParameterType == typeof(ILogger));
- }
-
- [Fact]
- public void ValidateEfControllerStep_Constructor_RequiresTelemetryService_Net11()
- {
- var ctor = typeof(ValidateEfControllerStep).GetConstructors().First();
- var parameters = ctor.GetParameters();
- Assert.Contains(parameters, p => p.ParameterType == typeof(ITelemetryService));
- }
-
- [Fact]
- public void ValidateEfControllerStep_Constructor_Has3Parameters_Net11()
- {
- var ctor = typeof(ValidateEfControllerStep).GetConstructors().First();
- Assert.Equal(3, ctor.GetParameters().Length);
- }
-
- #endregion
-
- #region ValidateEfControllerStep — Validation Logic
-
- [Fact]
- public async Task ValidateEfControllerStep_FailsWhenProjectMissing_Net11()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_FailsWhenProjectFileDoesNotExist_Net11()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_FailsWhenModelMissing_Net11()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = string.Empty,
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_FailsWhenControllerNameMissing_Net11()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = string.Empty,
- ControllerType = "API",
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_FailsWhenControllerTypeMissing_Net11()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = string.Empty,
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_FailsWhenDataContextMissing_Net11()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = string.Empty,
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_StepProperties_AreSetCorrectly_Net11()
- {
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer,
- Prerelease = true
- };
-
- Assert.Equal(_testProjectPath, step.Project);
- Assert.Equal("Product", step.Model);
- Assert.Equal("ProductsController", step.ControllerName);
- Assert.Equal("API", step.ControllerType);
- Assert.Equal("AppDbContext", step.DataContext);
- Assert.Equal(PackageConstants.EfConstants.SqlServer, step.DatabaseProvider);
- Assert.True(step.Prerelease);
- }
-
- #endregion
-
- #region Telemetry
-
- [Fact]
- public async Task TelemetryEventName_IsValidateEfControllerStepEvent_Net11()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext"
- };
-
- await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.Single(_testTelemetryService.TrackedEvents);
- Assert.Equal("ValidateEfControllerStepEvent", _testTelemetryService.TrackedEvents[0].EventName);
- }
-
- [Fact]
- public async Task TelemetryEvent_ContainsScaffolderNameProperty_Net11()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext"
- };
-
- await step.ExecuteAsync(_context, CancellationToken.None);
-
- var props = _testTelemetryService.TrackedEvents[0].Properties;
- Assert.True(props.ContainsKey("ScaffolderName"));
- Assert.Equal("API Controller with actions, using Entity Framework (CRUD)", props["ScaffolderName"]);
- }
-
- [Fact]
- public async Task TelemetryEvent_ContainsResultProperty_OnFailure_Net11()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext"
- };
-
- await step.ExecuteAsync(_context, CancellationToken.None);
-
- var props = _testTelemetryService.TrackedEvents[0].Properties;
- Assert.True(props.ContainsKey("Result"));
- Assert.Equal("Failure", props["Result"]);
- }
-
- [Fact]
- public async Task TelemetryEvent_SingleEventPerValidation_Net11()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = string.Empty,
- Model = string.Empty,
- ControllerName = string.Empty,
- ControllerType = string.Empty,
- DataContext = string.Empty
- };
-
- await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- #endregion
-
- #region EfControllerModel Properties
-
- [Fact]
- public void EfControllerModel_HasControllerTypeProperty_Net11()
- {
- Assert.NotNull(typeof(EfControllerModel).GetProperty("ControllerType"));
- }
-
- [Fact]
- public void EfControllerModel_HasControllerNameProperty_Net11()
- {
- Assert.NotNull(typeof(EfControllerModel).GetProperty("ControllerName"));
- }
-
- [Fact]
- public void EfControllerModel_HasControllerOutputPathProperty_Net11()
- {
- Assert.NotNull(typeof(EfControllerModel).GetProperty("ControllerOutputPath"));
- }
-
- [Fact]
- public void EfControllerModel_HasDbContextInfoProperty_Net11()
- {
- Assert.NotNull(typeof(EfControllerModel).GetProperty("DbContextInfo"));
- }
-
- [Fact]
- public void EfControllerModel_HasModelInfoProperty_Net11()
- {
- Assert.NotNull(typeof(EfControllerModel).GetProperty("ModelInfo"));
- }
-
- [Fact]
- public void EfControllerModel_HasProjectInfoProperty_Net11()
- {
- Assert.NotNull(typeof(EfControllerModel).GetProperty("ProjectInfo"));
- }
-
- [Fact]
- public void EfControllerModel_Has6Properties_Net11()
- {
- var props = typeof(EfControllerModel).GetProperties(BindingFlags.Public | BindingFlags.Instance);
- Assert.Equal(6, props.Length);
- }
-
- #endregion
-
- #region EfControllerSettings Properties
-
- [Fact]
- public void EfControllerSettings_HasControllerTypeProperty_Net11()
- {
- Assert.NotNull(typeof(EfControllerSettings).GetProperty("ControllerType"));
- }
-
- [Fact]
- public void EfControllerSettings_HasControllerNameProperty_Net11()
- {
- Assert.NotNull(typeof(EfControllerSettings).GetProperty("ControllerName"));
- }
-
- [Fact]
- public void EfControllerSettings_InheritsFromEfWithModelStepSettings_Net11()
- {
- Assert.True(typeof(EfControllerSettings).IsAssignableTo(typeof(EfWithModelStepSettings)));
- }
-
- [Fact]
- public void EfControllerSettings_HasProjectProperty_Net11()
- {
- Assert.NotNull(typeof(EfControllerSettings).GetProperty("Project"));
- }
-
- [Fact]
- public void EfControllerSettings_HasModelProperty_Net11()
- {
- Assert.NotNull(typeof(EfControllerSettings).GetProperty("Model"));
- }
-
- [Fact]
- public void EfControllerSettings_HasDataContextProperty_Net11()
- {
- Assert.NotNull(typeof(EfControllerSettings).GetProperty("DataContext"));
- }
-
- [Fact]
- public void EfControllerSettings_HasDatabaseProviderProperty_Net11()
- {
- Assert.NotNull(typeof(EfControllerSettings).GetProperty("DatabaseProvider"));
- }
-
- [Fact]
- public void EfControllerSettings_HasPrereleaseProperty_Net11()
- {
- Assert.NotNull(typeof(EfControllerSettings).GetProperty("Prerelease"));
- }
-
- #endregion
-
- #region EfWithModelStepSettings Properties
-
- [Fact]
- public void EfWithModelStepSettings_InheritsFromBaseSettings_Net11()
- {
- Assert.True(typeof(EfWithModelStepSettings).IsAssignableTo(typeof(BaseSettings)));
- }
-
- [Fact]
- public void EfWithModelStepSettings_HasDatabaseProviderProperty_Net11()
- {
- Assert.NotNull(typeof(EfWithModelStepSettings).GetProperty("DatabaseProvider"));
- }
-
- [Fact]
- public void EfWithModelStepSettings_HasDataContextProperty_Net11()
- {
- Assert.NotNull(typeof(EfWithModelStepSettings).GetProperty("DataContext"));
- }
-
- [Fact]
- public void EfWithModelStepSettings_HasModelProperty_Net11()
- {
- Assert.NotNull(typeof(EfWithModelStepSettings).GetProperty("Model"));
- }
-
- [Fact]
- public void EfWithModelStepSettings_HasPrereleaseProperty_Net11()
- {
- Assert.NotNull(typeof(EfWithModelStepSettings).GetProperty("Prerelease"));
- }
-
- #endregion
-
- #region BaseSettings Properties
-
- [Fact]
- public void BaseSettings_HasProjectProperty_Net11()
- {
- Assert.NotNull(typeof(BaseSettings).GetProperty("Project"));
- }
-
- [Fact]
- public void BaseSettings_IsInternal_Net11()
- {
- Assert.False(typeof(BaseSettings).IsPublic);
- }
-
- #endregion
-
- #region DbContextInfo Properties
-
- [Fact]
- public void DbContextInfo_HasDbContextClassNameProperty_Net11()
- {
- Assert.NotNull(typeof(DbContextInfo).GetProperty("DbContextClassName"));
- }
-
- [Fact]
- public void DbContextInfo_HasDbContextClassPathProperty_Net11()
- {
- Assert.NotNull(typeof(DbContextInfo).GetProperty("DbContextClassPath"));
- }
-
- [Fact]
- public void DbContextInfo_HasDbContextNamespaceProperty_Net11()
- {
- Assert.NotNull(typeof(DbContextInfo).GetProperty("DbContextNamespace"));
- }
-
- [Fact]
- public void DbContextInfo_HasDatabaseProviderProperty_Net11()
- {
- Assert.NotNull(typeof(DbContextInfo).GetProperty("DatabaseProvider"));
- }
-
- [Fact]
- public void DbContextInfo_HasEfScenarioProperty_Net11()
- {
- Assert.NotNull(typeof(DbContextInfo).GetProperty("EfScenario"));
- }
-
- [Fact]
- public void DbContextInfo_DefaultEfScenario_IsFalse_Net11()
- {
- var info = new DbContextInfo();
- Assert.False(info.EfScenario);
- }
-
- #endregion
-
- #region ModelInfo Properties
-
- [Fact]
- public void ModelInfo_HasModelTypeNameProperty_Net11()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("ModelTypeName"));
- }
-
- [Fact]
- public void ModelInfo_HasModelNamespaceProperty_Net11()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("ModelNamespace"));
- }
-
- [Fact]
- public void ModelInfo_HasModelFullNameProperty_Net11()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("ModelFullName"));
- }
-
- [Fact]
- public void ModelInfo_HasModelTypeNameCapitalizedProperty_Net11()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("ModelTypeNameCapitalized"));
- }
-
- [Fact]
- public void ModelInfo_HasModelTypePluralNameProperty_Net11()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("ModelTypePluralName"));
- }
-
- [Fact]
- public void ModelInfo_HasModelVariableProperty_Net11()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("ModelVariable"));
- }
-
- [Fact]
- public void ModelInfo_HasPrimaryKeyNameProperty_Net11()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("PrimaryKeyName"));
- }
-
- [Fact]
- public void ModelInfo_HasPrimaryKeyShortTypeNameProperty_Net11()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("PrimaryKeyShortTypeName"));
- }
-
- [Fact]
- public void ModelInfo_HasPrimaryKeyTypeNameProperty_Net11()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("PrimaryKeyTypeName"));
- }
-
- [Fact]
- public void ModelInfo_ComputedProperties_WorkCorrectly_Net11()
- {
- var modelInfo = new ModelInfo { ModelTypeName = "product" };
- Assert.Equal("Product", modelInfo.ModelTypeNameCapitalized);
- Assert.Equal("products", modelInfo.ModelTypePluralName);
- Assert.Equal("product", modelInfo.ModelVariable);
- }
-
- #endregion
-
- #region PackageConstants — EF
-
- [Fact]
- public void PackageConstants_SqlServer_HasCorrectKey_Net11()
- {
- Assert.Equal("sqlserver-efcore", PackageConstants.EfConstants.SqlServer);
- }
-
- [Fact]
- public void PackageConstants_SQLite_HasCorrectKey_Net11()
- {
- Assert.Equal("sqlite-efcore", PackageConstants.EfConstants.SQLite);
- }
-
- [Fact]
- public void PackageConstants_CosmosDb_HasCorrectKey_Net11()
- {
- Assert.Equal("cosmos-efcore", PackageConstants.EfConstants.CosmosDb);
- }
-
- [Fact]
- public void PackageConstants_Postgres_HasCorrectKey_Net11()
- {
- Assert.Equal("npgsql-efcore", PackageConstants.EfConstants.Postgres);
- }
-
- [Fact]
- public void PackageConstants_EfCorePackage_HasCorrectName_Net11()
- {
- Assert.Equal("Microsoft.EntityFrameworkCore", PackageConstants.EfConstants.EfCorePackage.Name);
- }
-
- [Fact]
- public void PackageConstants_EfCorePackage_RequiresVersion_Net11()
- {
- Assert.True(PackageConstants.EfConstants.EfCorePackage.IsVersionRequired);
- }
-
- [Fact]
- public void PackageConstants_EfCoreToolsPackage_HasCorrectName_Net11()
- {
- Assert.Equal("Microsoft.EntityFrameworkCore.Tools", PackageConstants.EfConstants.EfCoreToolsPackage.Name);
- }
-
- [Fact]
- public void PackageConstants_EfCoreToolsPackage_RequiresVersion_Net11()
- {
- Assert.True(PackageConstants.EfConstants.EfCoreToolsPackage.IsVersionRequired);
- }
-
- [Fact]
- public void PackageConstants_SqlServerPackage_HasCorrectName_Net11()
- {
- Assert.Equal("Microsoft.EntityFrameworkCore.SqlServer", PackageConstants.EfConstants.SqlServerPackage.Name);
- }
-
- [Fact]
- public void PackageConstants_SqlitePackage_HasCorrectName_Net11()
- {
- Assert.Equal("Microsoft.EntityFrameworkCore.Sqlite", PackageConstants.EfConstants.SqlitePackage.Name);
- }
-
- [Fact]
- public void PackageConstants_CosmosPackage_HasCorrectName_Net11()
- {
- Assert.Equal("Microsoft.EntityFrameworkCore.Cosmos", PackageConstants.EfConstants.CosmosPackage.Name);
- }
-
- [Fact]
- public void PackageConstants_PostgresPackage_HasCorrectName_Net11()
- {
- Assert.Equal("Npgsql.EntityFrameworkCore.PostgreSQL", PackageConstants.EfConstants.PostgresPackage.Name);
- }
-
- [Fact]
- public void PackageConstants_EfPackagesDict_Contains4Providers_Net11()
- {
- Assert.Equal(4, PackageConstants.EfConstants.EfPackagesDict.Count);
- }
-
- [Fact]
- public void PackageConstants_EfPackagesDict_ContainsSqlServer_Net11()
- {
- Assert.True(PackageConstants.EfConstants.EfPackagesDict.ContainsKey(PackageConstants.EfConstants.SqlServer));
- }
-
- [Fact]
- public void PackageConstants_EfPackagesDict_ContainsSQLite_Net11()
- {
- Assert.True(PackageConstants.EfConstants.EfPackagesDict.ContainsKey(PackageConstants.EfConstants.SQLite));
- }
-
- [Fact]
- public void PackageConstants_EfPackagesDict_ContainsCosmosDb_Net11()
- {
- Assert.True(PackageConstants.EfConstants.EfPackagesDict.ContainsKey(PackageConstants.EfConstants.CosmosDb));
- }
-
- [Fact]
- public void PackageConstants_EfPackagesDict_ContainsPostgres_Net11()
- {
- Assert.True(PackageConstants.EfConstants.EfPackagesDict.ContainsKey(PackageConstants.EfConstants.Postgres));
- }
-
- [Fact]
- public void PackageConstants_ConnectionStringVariableName_IsCorrect_Net11()
- {
- Assert.Equal("connectionString", PackageConstants.EfConstants.ConnectionStringVariableName);
- }
-
- #endregion
-
- #region UseDatabaseMethods
-
- [Fact]
- public void UseDatabaseMethods_SqlServer_UseSqlServer_Net11()
- {
- Assert.True(PackageConstants.EfConstants.UseDatabaseMethods.ContainsKey(PackageConstants.EfConstants.SqlServer));
- Assert.Equal("UseSqlServer", PackageConstants.EfConstants.UseDatabaseMethods[PackageConstants.EfConstants.SqlServer]);
- }
-
- [Fact]
- public void UseDatabaseMethods_SQLite_UseSqlite_Net11()
- {
- Assert.True(PackageConstants.EfConstants.UseDatabaseMethods.ContainsKey(PackageConstants.EfConstants.SQLite));
- Assert.Equal("UseSqlite", PackageConstants.EfConstants.UseDatabaseMethods[PackageConstants.EfConstants.SQLite]);
- }
-
- [Fact]
- public void UseDatabaseMethods_Postgres_UseNpgsql_Net11()
- {
- Assert.True(PackageConstants.EfConstants.UseDatabaseMethods.ContainsKey(PackageConstants.EfConstants.Postgres));
- Assert.Equal("UseNpgsql", PackageConstants.EfConstants.UseDatabaseMethods[PackageConstants.EfConstants.Postgres]);
- }
-
- [Fact]
- public void UseDatabaseMethods_CosmosDb_UseCosmos_Net11()
- {
- Assert.True(PackageConstants.EfConstants.UseDatabaseMethods.ContainsKey(PackageConstants.EfConstants.CosmosDb));
- Assert.Equal("UseCosmos", PackageConstants.EfConstants.UseDatabaseMethods[PackageConstants.EfConstants.CosmosDb]);
- }
-
- #endregion
-
- #region Template Folder Verification — Net11 (.tt text template format)
-
- [Fact]
- public void Net11TemplateFolder_ContainsApiEfControllerTtTemplate_Net11()
- {
- var assembly = typeof(EfControllerHelper).Assembly;
- string basePath = Path.GetDirectoryName(assembly.Location)!;
- string templatePath = Path.Combine(basePath, "Templates", TargetFramework, "EfController", "ApiEfController.tt");
-
- if (File.Exists(templatePath))
- {
- string content = File.ReadAllText(templatePath);
- Assert.NotEmpty(content);
- }
- else
- {
- // .tt templates compiled into the assembly; no physical .tt file expected at runtime
- Assert.True(true, ".tt template compiled into assembly at build time");
- }
- }
-
- [Fact]
- public void Net11TemplateFolder_ContainsMvcEfControllerTtTemplate_Net11()
- {
- var assembly = typeof(EfControllerHelper).Assembly;
- string basePath = Path.GetDirectoryName(assembly.Location)!;
- string templatePath = Path.Combine(basePath, "Templates", TargetFramework, "EfController", "MvcEfController.tt");
-
- if (File.Exists(templatePath))
- {
- string content = File.ReadAllText(templatePath);
- Assert.NotEmpty(content);
- }
- else
- {
- Assert.True(true, ".tt template compiled into assembly at build time");
- }
- }
-
- [Fact]
- public void Net11TemplateFolder_DoesNotUseLegacyCshtmlTemplates_Net11()
- {
- // Net11 EfController folder should NOT have .cshtml templates (those are only in net8.0)
- var assembly = typeof(EfControllerHelper).Assembly;
- string basePath = Path.GetDirectoryName(assembly.Location)!;
- string efControllerDir = Path.Combine(basePath, "Templates", TargetFramework, "EfController");
-
- if (Directory.Exists(efControllerDir))
- {
- var cshtmlFiles = Directory.GetFiles(efControllerDir, "*.cshtml");
- Assert.Empty(cshtmlFiles);
- }
- else
- {
- // Templates compiled into assembly; no physical folder expected
- Assert.True(true);
- }
- }
-
- #endregion
-
- #region Net11 Template Compilation — .cs files compile normally (no Compile Remove)
-
- [Fact]
- public void Net11TemplateTypes_CsFilesCompileNormally_NoCompileRemove_Net11()
- {
- // Unlike net9.0 and net10.0 which have explicit entries,
- // net11.0 EfController .cs files have NO Compile Remove in the csproj.
- // They compile normally via the default **/*.cs globbing pattern as partial classes
- // in the Templates.net10.EfController namespace (same namespace as net10.0).
- var assembly = typeof(EfControllerHelper).Assembly;
- var allTypes = assembly.GetTypes();
- var net10EfControllerTypes = allTypes.Where(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.EfController")).ToList();
-
- // Both net10.0 and net11.0 .cs files contribute to these partial types
- Assert.True(net10EfControllerTypes.Count > 0,
- "Expected Templates.net10.EfController types (compiled from both net10.0 and net11.0 .cs partial classes)");
- }
-
- [Fact]
- public void Net11TemplateTypes_ApiEfController_ExistsInSharedNamespace_Net11()
- {
- // net11.0 ApiEfController.cs uses namespace Templates.net10.EfController (same as net10.0)
- var assembly = typeof(EfControllerHelper).Assembly;
- var apiType = assembly.GetTypes().FirstOrDefault(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.EfController") &&
- t.Name.Equals("ApiEfController", StringComparison.OrdinalIgnoreCase));
-
- Assert.NotNull(apiType);
- }
-
- [Fact]
- public void Net11TemplateTypes_MvcEfController_ExistsInSharedNamespace_Net11()
- {
- // net11.0 MvcEfController.cs uses namespace Templates.net10.EfController (same as net10.0)
- var assembly = typeof(EfControllerHelper).Assembly;
- var mvcType = assembly.GetTypes().FirstOrDefault(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.EfController") &&
- t.Name.Equals("MvcEfController", StringComparison.OrdinalIgnoreCase));
-
- Assert.NotNull(mvcType);
- }
-
- [Fact]
- public void Net11TemplateTypes_ApiEfController_IsPartialClass_Net11()
- {
- // net11.0 .cs files compile as partial classes alongside net10.0 .cs files
- var assembly = typeof(EfControllerHelper).Assembly;
- var apiType = assembly.GetTypes().FirstOrDefault(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.EfController") &&
- t.Name.Equals("ApiEfController", StringComparison.OrdinalIgnoreCase));
-
- Assert.NotNull(apiType);
- Assert.True(apiType!.IsClass);
- }
-
- [Fact]
- public void Net11TemplateTypes_MvcEfController_IsPartialClass_Net11()
- {
- // net11.0 .cs files compile as partial classes alongside net10.0 .cs files
- var assembly = typeof(EfControllerHelper).Assembly;
- var mvcType = assembly.GetTypes().FirstOrDefault(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.EfController") &&
- t.Name.Equals("MvcEfController", StringComparison.OrdinalIgnoreCase));
-
- Assert.NotNull(mvcType);
- Assert.True(mvcType!.IsClass);
- }
-
- #endregion
-
- #region EfControllerHelper — GetCrudControllerType uses Templates.net10 types
-
- [Fact]
- public void EfControllerHelper_GetCrudControllerType_MapsToNet10Namespace_Net11()
- {
- // GetCrudControllerType maps "ApiEfController.tt" and "MvcEfController.tt"
- // to Templates.net10.EfController types regardless of target TFM
- var assembly = typeof(EfControllerHelper).Assembly;
- var allTypes = assembly.GetTypes();
- var net10EfControllerTypes = allTypes.Where(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.EfController")).ToList();
-
- Assert.True(net10EfControllerTypes.Count > 0, "Expected net10 EfController template types in assembly");
- }
-
- [Fact]
- public void EfControllerHelper_ApiEfController_InCorrectNamespace_Net11()
- {
- var assembly = typeof(EfControllerHelper).Assembly;
- var apiType = assembly.GetTypes().FirstOrDefault(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.EfController") &&
- t.Name.Equals("ApiEfController", StringComparison.OrdinalIgnoreCase));
-
- Assert.NotNull(apiType);
- Assert.Contains("Templates.net10.EfController", apiType!.FullName);
- }
-
- [Fact]
- public void EfControllerHelper_MvcEfController_InCorrectNamespace_Net11()
- {
- var assembly = typeof(EfControllerHelper).Assembly;
- var mvcType = assembly.GetTypes().FirstOrDefault(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.EfController") &&
- t.Name.Equals("MvcEfController", StringComparison.OrdinalIgnoreCase));
-
- Assert.NotNull(mvcType);
- Assert.Contains("Templates.net10.EfController", mvcType!.FullName);
- }
-
- [Fact]
- public void EfControllerHelper_ThrowsWhenProjectInfoNull_Net11()
- {
- var model = new EfControllerModel
- {
- ControllerType = "API",
- ControllerName = "ProductsController",
- ControllerOutputPath = "Controllers",
- DbContextInfo = new DbContextInfo { DbContextClassName = "AppDbContext", EfScenario = true },
- ModelInfo = new ModelInfo { ModelTypeName = "Product" },
- ProjectInfo = new ProjectInfo(null)
- };
-
- Assert.Throws(() =>
- EfControllerHelper.GetEfControllerTemplatingProperty(model));
- }
-
- #endregion
-
- #region Code Modification Configs
-
- [Fact]
- public void Net11CodeModificationConfig_EfControllerChanges_Exists_Net11()
- {
- var assembly = typeof(EfControllerHelper).Assembly;
- string basePath = Path.GetDirectoryName(assembly.Location)!;
- string configPath = Path.Combine(basePath, "Templates", "net11.0", "CodeModificationConfigs", "efControllerChanges.json");
-
- if (File.Exists(configPath))
- {
- string content = File.ReadAllText(configPath);
- Assert.Contains("Program.cs", content);
- }
- else
- {
- Assert.True(true, "Config file expected embedded in assembly");
- }
- }
-
- #endregion
-
- #region Pipeline Step Sequence
-
- [Fact]
- public void ApiControllerCrudPipeline_DefinesCorrectStepSequence_Net11()
- {
- // API Controller CRUD pipeline: ValidateEfControllerStep → WithEfControllerAddPackagesStep → WithDbContextStep
- // → WithAspNetConnectionStringStep → WithEfControllerTextTemplatingStep → WithEfControllerCodeChangeStep
- Assert.NotNull(typeof(ValidateEfControllerStep));
- Assert.True(typeof(ValidateEfControllerStep).IsClass);
+ protected override string TargetFramework => "net11.0";
+ protected override string TestClassName => nameof(ApiControllerNet11IntegrationTests);
+
+ [Fact]
+ public async Task Scaffold_ApiControllerCrud_Net11_CliInvocation()
+ {
+ // Arrange — set up project with Program.cs and a model class
+ var projectContent = ProjectContent.Replace(
+ "",
+ " false\n ");
+ File.WriteAllText(_testProjectPath, projectContent);
+
+ // Write NuGet.config with preview feeds so net11.0 packages can be resolved
+ File.WriteAllText(Path.Combine(_testProjectDir, "NuGet.config"), ScaffoldCliHelper.PreviewNuGetConfig);
+ File.WriteAllText(Path.Combine(_testProjectDir, "Program.cs"), ScaffoldCliHelper.GetMinimalProgramCs());
+ var modelsDir = Path.Combine(_testProjectDir, "Models");
+ Directory.CreateDirectory(modelsDir);
+ File.WriteAllText(Path.Combine(modelsDir, "TestModel.cs"), ScaffoldCliHelper.GetModelClassContent("TestProject", "TestModel"));
+
+ // Verify project builds before scaffolding
+ var (beforeExitCode, _, beforeError) = await RunBuildAsync(_testProjectDir);
+ Assert.True(beforeExitCode == 0, $"Project should build before scaffolding. Error: {beforeError}");
+
+ // Act — invoke CLI: dotnet scaffold aspnet apicontroller-crud
+ var (cliExitCode, cliOutput, cliError) = await ScaffoldCliHelper.RunScaffoldAsync(
+ TargetFramework,
+ "apicontroller-crud",
+ "--project", _testProjectPath,
+ "--model", "TestModel",
+ "--controller", "TestApiController",
+ "--dataContext", "TestDbContext",
+ "--dbProvider", "sqlite-efcore",
+ "--prerelease");
+ Assert.True(cliExitCode == 0, $"CLI scaffold should succeed.\nOutput: {cliOutput}\nError: {cliError}");
+
+ // Assert — expected files were created
+ Assert.True(File.Exists(Path.Combine(_testProjectDir, "Controllers", "TestApiController.cs")),
+ "Controller file 'Controllers/TestApiController.cs' should be created.");
+ Assert.True(File.Exists(Path.Combine(_testProjectDir, "Data", "TestDbContext.cs")),
+ "DbContext file 'Data/TestDbContext.cs' should be created.");
+ var programContent = File.ReadAllText(Path.Combine(_testProjectDir, "Program.cs"));
+ Assert.Contains("TestDbContext", programContent);
+
+ // Assert no NuGet errors during scaffolding
+ Assert.False(cliOutput.Contains("error: NU"),
+ $"Scaffolding should not produce NuGet errors for {TargetFramework}.\nOutput: {cliOutput}");
+
+ // Verify project builds after scaffolding
+ var (afterExitCode, _, afterError) = await RunBuildAsync(_testProjectDir);
+ Assert.True(afterExitCode == 0, $"Project should still build after scaffolding. Error: {afterError}");
}
-
- [Fact]
- public void MvcControllerCrudPipeline_HasAdditionalMvcViewsStep_Net11()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions);
- var method = extensionType.GetMethod("WithMvcViewsStep", BindingFlags.Public | BindingFlags.Static);
- Assert.NotNull(method);
- }
-
- [Fact]
- public void EfControllerPipeline_AllKeyStepsInheritFromScaffoldStep_Net11()
- {
- Assert.True(typeof(ValidateEfControllerStep).IsAssignableTo(typeof(ScaffoldStep)));
- }
-
- [Fact]
- public void EfControllerPipeline_AllKeyStepsAreInScaffoldStepsNamespace_Net11()
- {
- string expectedNs = "Microsoft.DotNet.Tools.Scaffold.AspNet.ScaffoldSteps";
- Assert.Equal(expectedNs, typeof(ValidateEfControllerStep).Namespace);
- }
-
- #endregion
-
- #region Builder Extensions
-
- [Fact]
- public void EfControllerBuilderExtensions_WithEfControllerTextTemplatingStep_Exists_Net11()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions);
- var method = extensionType.GetMethod("WithEfControllerTextTemplatingStep", BindingFlags.Public | BindingFlags.Static);
- Assert.NotNull(method);
- }
-
- [Fact]
- public void EfControllerBuilderExtensions_WithEfControllerAddPackagesStep_Exists_Net11()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions);
- var method = extensionType.GetMethod("WithEfControllerAddPackagesStep", BindingFlags.Public | BindingFlags.Static);
- Assert.NotNull(method);
- }
-
- [Fact]
- public void EfControllerBuilderExtensions_WithEfControllerCodeChangeStep_Exists_Net11()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions);
- var method = extensionType.GetMethod("WithEfControllerCodeChangeStep", BindingFlags.Public | BindingFlags.Static);
- Assert.NotNull(method);
- }
-
- [Fact]
- public void EfControllerBuilderExtensions_WithMvcViewsStep_Exists_Net11()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions);
- var method = extensionType.GetMethod("WithMvcViewsStep", BindingFlags.Public | BindingFlags.Static);
- Assert.NotNull(method);
- }
-
- [Fact]
- public void EfControllerBuilderExtensions_Has4ExtensionMethods_Net11()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions);
- var methods = extensionType.GetMethods(BindingFlags.Public | BindingFlags.Static)
- .Where(m => m.GetParameters().Any(p => p.ParameterType == typeof(IScaffoldBuilder)))
- .ToList();
- Assert.Equal(4, methods.Count);
- }
-
- [Fact]
- public void EfControllerBuilderExtensions_AllMethodsReturnIScaffoldBuilder_Net11()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions);
- var methods = extensionType.GetMethods(BindingFlags.Public | BindingFlags.Static)
- .Where(m => m.GetParameters().Any(p => p.ParameterType == typeof(IScaffoldBuilder)))
- .ToList();
-
- foreach (var method in methods)
- {
- Assert.Equal(typeof(IScaffoldBuilder), method.ReturnType);
- }
- }
-
- #endregion
-
- #region TFM Availability
-
- [Fact]
- public void ApiControllerCrud_IsAvailableForNet11_Net11()
- {
- Assert.Equal("API", AspnetStrings.Catagories.API);
- }
-
- [Fact]
- public void MvcControllerCrud_IsAvailableForNet11_Net11()
- {
- Assert.Equal("MVC", AspnetStrings.Catagories.MVC);
- }
-
- [Fact]
- public void CommandInfoExtensions_IsCommandAnAspNetCommand_Exists_Net11()
- {
- var method = typeof(CommandInfoExtensions).GetMethod("IsCommandAnAspNetCommand");
- Assert.NotNull(method);
- }
-
- #endregion
-
- #region Cancellation Support
-
- [Fact]
- public async Task ValidateEfControllerStep_AcceptsCancellationToken_Net11()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext"
- };
-
- using var cts = new CancellationTokenSource();
- bool result = await step.ExecuteAsync(_context, cts.Token);
-
- Assert.False(result);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_ExecuteAsync_IsInherited_Net11()
- {
- var method = typeof(ValidateEfControllerStep).GetMethod("ExecuteAsync", new[] { typeof(ScaffolderContext), typeof(CancellationToken) });
- Assert.NotNull(method);
- Assert.True(method!.IsVirtual);
- }
-
- #endregion
-
- #region Scaffolder Registration Constants
-
- [Fact]
- public void ApiControllerCrud_UsesCorrectName_Net11()
- {
- Assert.Equal("apicontroller-crud", AspnetStrings.Api.ApiControllerCrud);
- }
-
- [Fact]
- public void ApiControllerCrud_UsesCorrectDisplayName_Net11()
- {
- Assert.Equal("API Controller with actions, using Entity Framework (CRUD)", AspnetStrings.Api.ApiControllerCrudDisplayName);
- }
-
- [Fact]
- public void ApiControllerCrud_UsesCorrectCategory_Net11()
- {
- Assert.Equal("API", AspnetStrings.Catagories.API);
- }
-
- [Fact]
- public void ApiControllerCrud_UsesCorrectDescription_Net11()
- {
- Assert.Equal("Create an API controller with REST actions to create, read, update, delete, and list entities", AspnetStrings.Api.ApiControllerCrudDescription);
- }
-
- [Fact]
- public void ApiControllerCrud_Has2Examples_Net11()
- {
- Assert.NotEmpty(AspnetStrings.Api.ApiControllerCrudExample1);
- Assert.NotEmpty(AspnetStrings.Api.ApiControllerCrudExample2);
- Assert.NotEmpty(AspnetStrings.Api.ApiControllerCrudExample1Description);
- Assert.NotEmpty(AspnetStrings.Api.ApiControllerCrudExample2Description);
- }
-
- [Fact]
- public void MvcControllerCrud_Has2Examples_Net11()
- {
- Assert.NotEmpty(AspnetStrings.MVC.ControllerCrudExample1);
- Assert.NotEmpty(AspnetStrings.MVC.ControllerCrudExample2);
- Assert.NotEmpty(AspnetStrings.MVC.ControllerCrudExample1Description);
- Assert.NotEmpty(AspnetStrings.MVC.ControllerCrudExample2Description);
- }
-
- #endregion
-
- #region Scaffolding Context Properties
-
- [Fact]
- public void ScaffolderContext_CanStoreEfControllerModel_Net11()
- {
- var model = new EfControllerModel
- {
- ControllerType = "API",
- ControllerName = "ProductsController",
- ControllerOutputPath = Path.Combine(_testProjectDir, "Controllers"),
- DbContextInfo = new DbContextInfo { DbContextClassName = "AppDbContext", EfScenario = true },
- ModelInfo = new ModelInfo { ModelTypeName = "Product" },
- ProjectInfo = new ProjectInfo(_testProjectPath)
- };
-
- _context.Properties.Add(nameof(EfControllerModel), model);
-
- Assert.True(_context.Properties.ContainsKey(nameof(EfControllerModel)));
- var retrieved = _context.Properties[nameof(EfControllerModel)] as EfControllerModel;
- Assert.NotNull(retrieved);
- Assert.Equal("API", retrieved!.ControllerType);
- Assert.Equal("ProductsController", retrieved.ControllerName);
- Assert.Equal("Product", retrieved.ModelInfo.ModelTypeName);
- Assert.True(retrieved.DbContextInfo.EfScenario);
- }
-
- [Fact]
- public void ScaffolderContext_CanStoreEfControllerSettings_Net11()
- {
- var settings = new EfControllerSettings
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer,
- Prerelease = false
- };
-
- _context.Properties.Add(nameof(EfControllerSettings), settings);
-
- Assert.True(_context.Properties.ContainsKey(nameof(EfControllerSettings)));
- var retrieved = _context.Properties[nameof(EfControllerSettings)] as EfControllerSettings;
- Assert.NotNull(retrieved);
- Assert.Equal(_testProjectPath, retrieved!.Project);
- Assert.Equal("API", retrieved.ControllerType);
- Assert.Equal("Product", retrieved.Model);
- }
-
- [Fact]
- public void ScaffolderContext_CanStoreCodeModifierProperties_Net11()
- {
- var codeModifierProperties = new Dictionary
- {
- { "DbContextName", "AppDbContext" },
- { "ConnectionStringName", "DefaultConnection" }
- };
-
- _context.Properties.Add(Scaffolding.Internal.Constants.StepConstants.CodeModifierProperties, codeModifierProperties);
-
- Assert.True(_context.Properties.ContainsKey(Scaffolding.Internal.Constants.StepConstants.CodeModifierProperties));
- var retrieved = _context.Properties[Scaffolding.Internal.Constants.StepConstants.CodeModifierProperties] as Dictionary;
- Assert.NotNull(retrieved);
- Assert.Equal(2, retrieved!.Count);
- }
-
- #endregion
-
- #region ControllerOutputPath Constant
-
- [Fact]
- public void ControllerCommandOutput_IsControllers_Net11()
- {
- Assert.Equal("Controllers", AspNetConstants.DotnetCommands.ControllerCommandOutput);
- }
-
- #endregion
-
- #region NewDbContext Constant
-
- [Fact]
- public void NewDbContext_HasCorrectValue_Net11()
- {
- Assert.Equal("NewDbContext", AspNetConstants.NewDbContext);
- }
-
- #endregion
-
- #region File Extensions
-
- [Fact]
- public void CSharpExtension_IsCorrect_Net11()
- {
- Assert.Equal(".cs", AspNetConstants.CSharpExtension);
- }
-
- #endregion
-
- #region Validation Combination Tests
-
- [Fact]
- public async Task ValidateEfControllerStep_NullProject_FailsValidation_Net11()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = null,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext"
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_NullModel_FailsValidation_Net11()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = null,
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext"
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_NullControllerName_FailsValidation_Net11()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = null,
- ControllerType = "API",
- DataContext = "AppDbContext"
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_NullControllerType_FailsValidation_Net11()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = null,
- DataContext = "AppDbContext"
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_NullDataContext_FailsValidation_Net11()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = null
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_AllFieldsEmpty_FailsValidation_Net11()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = string.Empty,
- Model = string.Empty,
- ControllerName = string.Empty,
- ControllerType = string.Empty,
- DataContext = string.Empty
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- #endregion
-
- #region Regression Guards
-
- [Fact]
- public void EfControllerModel_IsInModelsNamespace_Net11()
- {
- Assert.Equal("Microsoft.DotNet.Tools.Scaffold.AspNet.Models", typeof(EfControllerModel).Namespace);
- }
-
- [Fact]
- public void EfControllerSettings_IsInSettingsNamespace_Net11()
- {
- Assert.Equal("Microsoft.DotNet.Tools.Scaffold.AspNet.ScaffoldSteps.Settings", typeof(EfControllerSettings).Namespace);
- }
-
- [Fact]
- public void EfControllerHelper_IsInHelpersNamespace_Net11()
- {
- Assert.Equal("Microsoft.DotNet.Tools.Scaffold.AspNet.Helpers", typeof(EfControllerHelper).Namespace);
- }
-
- [Fact]
- public void ValidateEfControllerStep_IsInternal_Net11()
- {
- Assert.False(typeof(ValidateEfControllerStep).IsPublic);
- }
-
- [Fact]
- public void EfControllerModel_IsInternal_Net11()
- {
- Assert.False(typeof(EfControllerModel).IsPublic);
- }
-
- [Fact]
- public void EfControllerSettings_IsInternal_Net11()
- {
- Assert.False(typeof(EfControllerSettings).IsPublic);
- }
-
- [Fact]
- public void EfControllerScaffolderBuilderExtensions_IsInternal_Net11()
- {
- Assert.False(typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions).IsPublic);
- }
-
- [Fact]
- public void EfControllerHelper_IsInternal_Net11()
- {
- Assert.False(typeof(EfControllerHelper).IsPublic);
- }
-
- [Fact]
- public void EfControllerHelper_IsStatic_Net11()
- {
- Assert.True(typeof(EfControllerHelper).IsAbstract && typeof(EfControllerHelper).IsSealed);
- }
-
- [Fact]
- public void DbContextInfo_IsInternal_Net11()
- {
- Assert.False(typeof(DbContextInfo).IsPublic);
- }
-
- [Fact]
- public void ModelInfo_IsInternal_Net11()
- {
- Assert.False(typeof(ModelInfo).IsPublic);
- }
-
- #endregion
-
- #region API Controller Scaffolder — Non-CRUD Strings
-
- [Fact]
- public void ApiControllerNonCrud_Name_IsApiController_Net11()
- {
- Assert.Equal("apicontroller", AspnetStrings.Api.ApiController);
- }
-
- [Fact]
- public void ApiControllerNonCrud_DisplayName_Net11()
- {
- Assert.Equal("API Controller", AspnetStrings.Api.ApiControllerDisplayName);
- }
-
- [Fact]
- public void MvcControllerNonCrud_Name_IsMvcController_Net11()
- {
- Assert.Equal("mvccontroller", AspnetStrings.MVC.Controller);
- }
-
- [Fact]
- public void MvcControllerNonCrud_DisplayName_Net11()
- {
- Assert.Equal("MVC Controller", AspnetStrings.MVC.DisplayName);
- }
-
- #endregion
-
- #region ControllerType Values
-
- [Fact]
- public void ControllerType_APIValue_MatchesCategoryName_Net11()
- {
- Assert.Equal("API", AspnetStrings.Catagories.API);
- }
-
- [Fact]
- public void ControllerType_MVCValue_MatchesCategoryName_Net11()
- {
- Assert.Equal("MVC", AspnetStrings.Catagories.MVC);
- }
-
- #endregion
-
- #region TestTelemetryService Helper
-
- private class TestTelemetryService : ITelemetryService
- {
- public List<(string EventName, IReadOnlyDictionary Properties, IReadOnlyDictionary Measurements)> TrackedEvents { get; } = new();
-
- public void TrackEvent(string eventName, IReadOnlyDictionary properties, IReadOnlyDictionary measurements)
- {
- TrackedEvents.Add((eventName, properties, measurements));
- }
-
- public void Flush()
- {
- }
- }
-
- #endregion
}
diff --git a/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/ApiControllerNet8IntegrationTests.cs b/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/ApiControllerNet8IntegrationTests.cs
index 6c5b64278..19854f4d5 100644
--- a/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/ApiControllerNet8IntegrationTests.cs
+++ b/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/ApiControllerNet8IntegrationTests.cs
@@ -1,1695 +1,55 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System;
-using System.Collections.Generic;
using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Threading;
using System.Threading.Tasks;
-using Microsoft.DotNet.Scaffolding.Core.Builder;
-using Microsoft.DotNet.Scaffolding.Core.ComponentModel;
-using Microsoft.DotNet.Scaffolding.Core.Scaffolders;
-using Microsoft.DotNet.Scaffolding.Core.Steps;
-using Microsoft.DotNet.Scaffolding.Internal.Services;
-using Microsoft.DotNet.Scaffolding.Internal.Telemetry;
-using Microsoft.DotNet.Scaffolding.TextTemplating;
-using Microsoft.DotNet.Tools.Scaffold.AspNet;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.Commands;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.Common;
-using AspNetConstants = Microsoft.DotNet.Tools.Scaffold.AspNet.Common.Constants;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.Helpers;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.Models;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.ScaffoldSteps;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.ScaffoldSteps.Settings;
-using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Logging.Abstractions;
-using Moq;
+using Microsoft.DotNet.Tools.Scaffold.Tests.Helpers;
using Xunit;
namespace Microsoft.DotNet.Tools.Scaffold.Tests.AspNet.Integration.API;
-///
-/// Integration tests for the API Controller CRUD (apicontroller-crud) scaffolder targeting .NET 8.
-/// Validates scaffolder definition constants, ValidateEfControllerStep validation logic,
-/// EfControllerModel/EfControllerSettings/EfWithModelStepSettings/BaseSettings properties,
-/// EfControllerHelper template resolution, template folder verification, code modification configs,
-/// package constants, pipeline registration, step dependencies, telemetry tracking,
-/// TFM availability, builder extensions, and database provider support.
-/// The API Controller CRUD scaffolder is available for all supported TFMs including .NET 8.
-/// .NET 8 EfController templates use legacy .cshtml format (ApiControllerWithContext.cshtml, MvcControllerWithContext.cshtml).
-///
-public class ApiControllerNet8IntegrationTests : IDisposable
+public class ApiControllerNet8IntegrationTests : ApiControllerIntegrationTestsBase
{
- private const string TargetFramework = "net8.0";
- private readonly string _testDirectory;
- private readonly string _testProjectDir;
- private readonly string _testProjectPath;
- private readonly Mock _mockFileSystem;
- private readonly TestTelemetryService _testTelemetryService;
- private readonly Mock _mockScaffolder;
- private readonly ScaffolderContext _context;
-
- public ApiControllerNet8IntegrationTests()
- {
- _testDirectory = Path.Combine(Path.GetTempPath(), "ApiControllerNet8IntegrationTests", Guid.NewGuid().ToString());
- _testProjectDir = Path.Combine(_testDirectory, "TestProject");
- _testProjectPath = Path.Combine(_testProjectDir, "TestProject.csproj");
- Directory.CreateDirectory(_testProjectDir);
-
- _mockFileSystem = new Mock();
- _testTelemetryService = new TestTelemetryService();
- _mockScaffolder = new Mock();
- _mockScaffolder.Setup(s => s.DisplayName).Returns(AspnetStrings.Api.ApiControllerCrudDisplayName);
- _mockScaffolder.Setup(s => s.Name).Returns(AspnetStrings.Api.ApiControllerCrud);
- _context = new ScaffolderContext(_mockScaffolder.Object);
- }
-
- public void Dispose()
- {
- if (Directory.Exists(_testDirectory))
- {
- try { Directory.Delete(_testDirectory, recursive: true); }
- catch { /* best-effort cleanup */ }
- }
- }
-
- #region Constants & Scaffolder Definition — API Controller CRUD
-
- [Fact]
- public void ScaffolderName_IsApiControllerCrud_Net8()
- {
- Assert.Equal("apicontroller-crud", AspnetStrings.Api.ApiControllerCrud);
- }
-
- [Fact]
- public void ScaffolderDisplayName_IsApiControllerCrudDisplayName_Net8()
- {
- Assert.Equal("API Controller with actions, using Entity Framework (CRUD)", AspnetStrings.Api.ApiControllerCrudDisplayName);
- }
-
- [Fact]
- public void ScaffolderDescription_IsApiControllerCrudDescription_Net8()
- {
- Assert.Equal("Create an API controller with REST actions to create, read, update, delete, and list entities", AspnetStrings.Api.ApiControllerCrudDescription);
- }
-
- [Fact]
- public void ScaffolderCategory_IsAPI_Net8()
- {
- Assert.Equal("API", AspnetStrings.Catagories.API);
- }
-
- [Fact]
- public void ScaffolderExample1_ContainsApiControllerCrudCommand_Net8()
- {
- Assert.Contains("apicontroller-crud", AspnetStrings.Api.ApiControllerCrudExample1);
- }
-
- [Fact]
- public void ScaffolderExample1_ContainsRequiredOptions_Net8()
- {
- Assert.Contains("--project", AspnetStrings.Api.ApiControllerCrudExample1);
- Assert.Contains("--model", AspnetStrings.Api.ApiControllerCrudExample1);
- Assert.Contains("--controller-name", AspnetStrings.Api.ApiControllerCrudExample1);
- Assert.Contains("--data-context", AspnetStrings.Api.ApiControllerCrudExample1);
- Assert.Contains("--database-provider", AspnetStrings.Api.ApiControllerCrudExample1);
- }
-
- [Fact]
- public void ScaffolderExample2_ContainsApiControllerCrudCommand_Net8()
- {
- Assert.Contains("apicontroller-crud", AspnetStrings.Api.ApiControllerCrudExample2);
- }
-
- [Fact]
- public void ScaffolderExample2_ContainsPrerelease_Net8()
- {
- Assert.Contains("--prerelease", AspnetStrings.Api.ApiControllerCrudExample2);
- }
-
- [Fact]
- public void ScaffolderExample1Description_MentionsCrudOperations_Net8()
- {
- Assert.Contains("CRUD", AspnetStrings.Api.ApiControllerCrudExample1Description);
- }
-
- [Fact]
- public void ScaffolderExample2Description_MentionsPostgreSQL_Net8()
- {
- Assert.Contains("PostgreSQL", AspnetStrings.Api.ApiControllerCrudExample2Description);
- }
-
- #endregion
-
- #region Constants & Scaffolder Definition — MVC Controller CRUD
-
- [Fact]
- public void MVC_ScaffolderName_IsMvcControllerCrud_Net8()
- {
- Assert.Equal("mvccontroller-crud", AspnetStrings.MVC.ControllerCrud);
- }
-
- [Fact]
- public void MVC_ScaffolderDisplayName_IsMvcControllerCrudDisplayName_Net8()
- {
- Assert.Equal("MVC Controller with views, using Entity Framework (CRUD)", AspnetStrings.MVC.CrudDisplayName);
- }
-
- [Fact]
- public void MVC_ScaffolderDescription_IsMvcControllerCrudDescription_Net8()
- {
- Assert.Equal("Create a MVC controller with read/write actions and views using Entity Framework", AspnetStrings.MVC.CrudDescription);
- }
-
- [Fact]
- public void MVC_ScaffolderCategory_IsMVC_Net8()
- {
- Assert.Equal("MVC", AspnetStrings.Catagories.MVC);
- }
-
- [Fact]
- public void MVC_ScaffolderExample1_ContainsMvcControllerCrudCommand_Net8()
- {
- Assert.Contains("mvccontroller-crud", AspnetStrings.MVC.ControllerCrudExample1);
- }
-
- [Fact]
- public void MVC_ScaffolderExample1_ContainsViewsOption_Net8()
- {
- Assert.Contains("--views", AspnetStrings.MVC.ControllerCrudExample1);
- }
-
- #endregion
-
- #region CLI Options
-
- [Fact]
- public void CliOption_ProjectOption_IsCorrect_Net8()
- {
- Assert.Equal("--project", AspNetConstants.CliOptions.ProjectCliOption);
- }
-
- [Fact]
- public void CliOption_ModelOption_IsCorrect_Net8()
- {
- Assert.Equal("--model", AspNetConstants.CliOptions.ModelCliOption);
- }
-
- [Fact]
- public void CliOption_DataContextOption_IsCorrect_Net8()
- {
- Assert.Equal("--dataContext", AspNetConstants.CliOptions.DataContextOption);
- }
-
- [Fact]
- public void CliOption_DbProviderOption_IsCorrect_Net8()
- {
- Assert.Equal("--dbProvider", AspNetConstants.CliOptions.DbProviderOption);
- }
-
- [Fact]
- public void CliOption_ControllerNameOption_IsCorrect_Net8()
- {
- Assert.Equal("--controller", AspNetConstants.CliOptions.ControllerNameOption);
- }
-
- [Fact]
- public void CliOption_PrereleaseOption_IsCorrect_Net8()
- {
- Assert.Equal("--prerelease", AspNetConstants.CliOptions.PrereleaseCliOption);
- }
-
- [Fact]
- public void CliOption_ViewsOption_IsCorrect_Net8()
- {
- Assert.Equal("--views", AspNetConstants.CliOptions.ViewsOption);
- }
-
- #endregion
-
- #region AspNetOptions for EfController
-
- [Fact]
- public void AspNetOptions_HasModelNameProperty_Net8()
- {
- var prop = typeof(AspNetOptions).GetProperty("ModelName");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasControllerNameProperty_Net8()
- {
- var prop = typeof(AspNetOptions).GetProperty("ControllerName");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasDataContextClassRequiredProperty_Net8()
- {
- var prop = typeof(AspNetOptions).GetProperty("DataContextClassRequired");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasDatabaseProviderRequiredProperty_Net8()
- {
- var prop = typeof(AspNetOptions).GetProperty("DatabaseProviderRequired");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasPrereleaseProperty_Net8()
- {
- var prop = typeof(AspNetOptions).GetProperty("Prerelease");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasViewsProperty_Net8()
- {
- var prop = typeof(AspNetOptions).GetProperty("Views");
- Assert.NotNull(prop);
- }
-
- #endregion
-
- #region ValidateEfControllerStep — Properties and Construction
-
- [Fact]
- public void ValidateEfControllerStep_IsScaffoldStep_Net8()
- {
- Assert.True(typeof(ValidateEfControllerStep).IsAssignableTo(typeof(ScaffoldStep)));
- }
-
- [Fact]
- public void ValidateEfControllerStep_HasProjectProperty_Net8()
- {
- Assert.NotNull(typeof(ValidateEfControllerStep).GetProperty("Project"));
- }
-
- [Fact]
- public void ValidateEfControllerStep_HasPrereleaseProperty_Net8()
- {
- Assert.NotNull(typeof(ValidateEfControllerStep).GetProperty("Prerelease"));
- }
-
- [Fact]
- public void ValidateEfControllerStep_HasDatabaseProviderProperty_Net8()
- {
- Assert.NotNull(typeof(ValidateEfControllerStep).GetProperty("DatabaseProvider"));
- }
-
- [Fact]
- public void ValidateEfControllerStep_HasDataContextProperty_Net8()
- {
- Assert.NotNull(typeof(ValidateEfControllerStep).GetProperty("DataContext"));
- }
-
- [Fact]
- public void ValidateEfControllerStep_HasModelProperty_Net8()
- {
- Assert.NotNull(typeof(ValidateEfControllerStep).GetProperty("Model"));
- }
-
- [Fact]
- public void ValidateEfControllerStep_HasControllerNameProperty_Net8()
- {
- Assert.NotNull(typeof(ValidateEfControllerStep).GetProperty("ControllerName"));
- }
-
- [Fact]
- public void ValidateEfControllerStep_HasControllerTypeProperty_Net8()
- {
- Assert.NotNull(typeof(ValidateEfControllerStep).GetProperty("ControllerType"));
- }
-
- [Fact]
- public void ValidateEfControllerStep_Has7Properties_Net8()
- {
- // Project, Prerelease, DatabaseProvider, DataContext, Model, ControllerName, ControllerType
- var props = typeof(ValidateEfControllerStep).GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
- Assert.Equal(7, props.Length);
- }
-
- [Fact]
- public void ValidateEfControllerStep_Constructor_RequiresFileSystem_Net8()
- {
- var ctor = typeof(ValidateEfControllerStep).GetConstructors().First();
- var parameters = ctor.GetParameters();
- Assert.Contains(parameters, p => p.ParameterType == typeof(IFileSystem));
- }
-
- [Fact]
- public void ValidateEfControllerStep_Constructor_RequiresLogger_Net8()
- {
- var ctor = typeof(ValidateEfControllerStep).GetConstructors().First();
- var parameters = ctor.GetParameters();
- Assert.Contains(parameters, p => p.ParameterType == typeof(ILogger));
- }
-
- [Fact]
- public void ValidateEfControllerStep_Constructor_RequiresTelemetryService_Net8()
- {
- var ctor = typeof(ValidateEfControllerStep).GetConstructors().First();
- var parameters = ctor.GetParameters();
- Assert.Contains(parameters, p => p.ParameterType == typeof(ITelemetryService));
- }
-
- [Fact]
- public void ValidateEfControllerStep_Constructor_Has3Parameters_Net8()
- {
- var ctor = typeof(ValidateEfControllerStep).GetConstructors().First();
- Assert.Equal(3, ctor.GetParameters().Length);
- }
-
- #endregion
-
- #region ValidateEfControllerStep — Validation Logic
-
- [Fact]
- public async Task ValidateEfControllerStep_FailsWhenProjectMissing_Net8()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_FailsWhenProjectFileDoesNotExist_Net8()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_FailsWhenModelMissing_Net8()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = string.Empty,
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_FailsWhenControllerNameMissing_Net8()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = string.Empty,
- ControllerType = "API",
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_FailsWhenControllerTypeMissing_Net8()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = string.Empty,
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_FailsWhenDataContextMissing_Net8()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = string.Empty,
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_StepProperties_AreSetCorrectly_Net8()
- {
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer,
- Prerelease = true
- };
-
- Assert.Equal(_testProjectPath, step.Project);
- Assert.Equal("Product", step.Model);
- Assert.Equal("ProductsController", step.ControllerName);
- Assert.Equal("API", step.ControllerType);
- Assert.Equal("AppDbContext", step.DataContext);
- Assert.Equal(PackageConstants.EfConstants.SqlServer, step.DatabaseProvider);
- Assert.True(step.Prerelease);
- }
-
- #endregion
-
- #region Telemetry
-
- [Fact]
- public async Task TelemetryEventName_IsValidateEfControllerStepEvent_Net8()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext"
- };
-
- await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.Single(_testTelemetryService.TrackedEvents);
- Assert.Equal("ValidateEfControllerStepEvent", _testTelemetryService.TrackedEvents[0].EventName);
- }
-
- [Fact]
- public async Task TelemetryEvent_ContainsScaffolderNameProperty_Net8()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext"
- };
-
- await step.ExecuteAsync(_context, CancellationToken.None);
-
- var props = _testTelemetryService.TrackedEvents[0].Properties;
- Assert.True(props.ContainsKey("ScaffolderName"));
- Assert.Equal("API Controller with actions, using Entity Framework (CRUD)", props["ScaffolderName"]);
- }
-
- [Fact]
- public async Task TelemetryEvent_ContainsResultProperty_OnFailure_Net8()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext"
- };
-
- await step.ExecuteAsync(_context, CancellationToken.None);
-
- var props = _testTelemetryService.TrackedEvents[0].Properties;
- Assert.True(props.ContainsKey("Result"));
- Assert.Equal("Failure", props["Result"]);
- }
-
- [Fact]
- public async Task TelemetryEvent_SingleEventPerValidation_Net8()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = string.Empty,
- Model = string.Empty,
- ControllerName = string.Empty,
- ControllerType = string.Empty,
- DataContext = string.Empty
- };
-
- await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- #endregion
-
- #region EfControllerModel Properties
-
- [Fact]
- public void EfControllerModel_HasControllerTypeProperty_Net8()
- {
- Assert.NotNull(typeof(EfControllerModel).GetProperty("ControllerType"));
- }
-
- [Fact]
- public void EfControllerModel_HasControllerNameProperty_Net8()
- {
- Assert.NotNull(typeof(EfControllerModel).GetProperty("ControllerName"));
- }
-
- [Fact]
- public void EfControllerModel_HasControllerOutputPathProperty_Net8()
- {
- Assert.NotNull(typeof(EfControllerModel).GetProperty("ControllerOutputPath"));
- }
-
- [Fact]
- public void EfControllerModel_HasDbContextInfoProperty_Net8()
- {
- Assert.NotNull(typeof(EfControllerModel).GetProperty("DbContextInfo"));
- }
-
- [Fact]
- public void EfControllerModel_HasModelInfoProperty_Net8()
- {
- Assert.NotNull(typeof(EfControllerModel).GetProperty("ModelInfo"));
- }
-
- [Fact]
- public void EfControllerModel_HasProjectInfoProperty_Net8()
- {
- Assert.NotNull(typeof(EfControllerModel).GetProperty("ProjectInfo"));
- }
-
- [Fact]
- public void EfControllerModel_Has6Properties_Net8()
- {
- var props = typeof(EfControllerModel).GetProperties(BindingFlags.Public | BindingFlags.Instance);
- Assert.Equal(6, props.Length);
- }
-
- #endregion
-
- #region EfControllerSettings Properties
-
- [Fact]
- public void EfControllerSettings_HasControllerTypeProperty_Net8()
- {
- Assert.NotNull(typeof(EfControllerSettings).GetProperty("ControllerType"));
- }
-
- [Fact]
- public void EfControllerSettings_HasControllerNameProperty_Net8()
- {
- Assert.NotNull(typeof(EfControllerSettings).GetProperty("ControllerName"));
- }
-
- [Fact]
- public void EfControllerSettings_InheritsFromEfWithModelStepSettings_Net8()
- {
- Assert.True(typeof(EfControllerSettings).IsAssignableTo(typeof(EfWithModelStepSettings)));
- }
-
- [Fact]
- public void EfControllerSettings_HasProjectProperty_Net8()
- {
- // Inherited from BaseSettings
- Assert.NotNull(typeof(EfControllerSettings).GetProperty("Project"));
- }
-
- [Fact]
- public void EfControllerSettings_HasModelProperty_Net8()
- {
- // Inherited from EfWithModelStepSettings
- Assert.NotNull(typeof(EfControllerSettings).GetProperty("Model"));
- }
-
- [Fact]
- public void EfControllerSettings_HasDataContextProperty_Net8()
- {
- // Inherited from EfWithModelStepSettings
- Assert.NotNull(typeof(EfControllerSettings).GetProperty("DataContext"));
- }
-
- [Fact]
- public void EfControllerSettings_HasDatabaseProviderProperty_Net8()
- {
- // Inherited from EfWithModelStepSettings
- Assert.NotNull(typeof(EfControllerSettings).GetProperty("DatabaseProvider"));
- }
-
- [Fact]
- public void EfControllerSettings_HasPrereleaseProperty_Net8()
- {
- // Inherited from EfWithModelStepSettings
- Assert.NotNull(typeof(EfControllerSettings).GetProperty("Prerelease"));
- }
-
- #endregion
-
- #region EfWithModelStepSettings Properties
-
- [Fact]
- public void EfWithModelStepSettings_InheritsFromBaseSettings_Net8()
- {
- Assert.True(typeof(EfWithModelStepSettings).IsAssignableTo(typeof(BaseSettings)));
- }
-
- [Fact]
- public void EfWithModelStepSettings_HasDatabaseProviderProperty_Net8()
- {
- Assert.NotNull(typeof(EfWithModelStepSettings).GetProperty("DatabaseProvider"));
- }
-
- [Fact]
- public void EfWithModelStepSettings_HasDataContextProperty_Net8()
- {
- Assert.NotNull(typeof(EfWithModelStepSettings).GetProperty("DataContext"));
- }
-
- [Fact]
- public void EfWithModelStepSettings_HasModelProperty_Net8()
- {
- Assert.NotNull(typeof(EfWithModelStepSettings).GetProperty("Model"));
- }
-
- [Fact]
- public void EfWithModelStepSettings_HasPrereleaseProperty_Net8()
- {
- Assert.NotNull(typeof(EfWithModelStepSettings).GetProperty("Prerelease"));
- }
-
- #endregion
-
- #region BaseSettings Properties
-
- [Fact]
- public void BaseSettings_HasProjectProperty_Net8()
- {
- Assert.NotNull(typeof(BaseSettings).GetProperty("Project"));
- }
-
- [Fact]
- public void BaseSettings_IsInternal_Net8()
- {
- Assert.False(typeof(BaseSettings).IsPublic);
- }
-
- #endregion
-
- #region DbContextInfo Properties
-
- [Fact]
- public void DbContextInfo_HasDbContextClassNameProperty_Net8()
- {
- Assert.NotNull(typeof(DbContextInfo).GetProperty("DbContextClassName"));
- }
-
- [Fact]
- public void DbContextInfo_HasDbContextClassPathProperty_Net8()
- {
- Assert.NotNull(typeof(DbContextInfo).GetProperty("DbContextClassPath"));
- }
-
- [Fact]
- public void DbContextInfo_HasDbContextNamespaceProperty_Net8()
- {
- Assert.NotNull(typeof(DbContextInfo).GetProperty("DbContextNamespace"));
- }
-
- [Fact]
- public void DbContextInfo_HasDatabaseProviderProperty_Net8()
- {
- Assert.NotNull(typeof(DbContextInfo).GetProperty("DatabaseProvider"));
- }
-
- [Fact]
- public void DbContextInfo_HasEfScenarioProperty_Net8()
- {
- Assert.NotNull(typeof(DbContextInfo).GetProperty("EfScenario"));
- }
-
- [Fact]
- public void DbContextInfo_DefaultEfScenario_IsFalse_Net8()
- {
- var info = new DbContextInfo();
- Assert.False(info.EfScenario);
- }
-
- #endregion
-
- #region ModelInfo Properties
-
- [Fact]
- public void ModelInfo_HasModelTypeNameProperty_Net8()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("ModelTypeName"));
- }
-
- [Fact]
- public void ModelInfo_HasModelNamespaceProperty_Net8()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("ModelNamespace"));
- }
-
- [Fact]
- public void ModelInfo_HasModelFullNameProperty_Net8()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("ModelFullName"));
- }
-
- [Fact]
- public void ModelInfo_HasModelTypeNameCapitalizedProperty_Net8()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("ModelTypeNameCapitalized"));
- }
-
- [Fact]
- public void ModelInfo_HasModelTypePluralNameProperty_Net8()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("ModelTypePluralName"));
- }
-
- [Fact]
- public void ModelInfo_HasModelVariableProperty_Net8()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("ModelVariable"));
- }
-
- [Fact]
- public void ModelInfo_HasPrimaryKeyNameProperty_Net8()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("PrimaryKeyName"));
- }
-
- [Fact]
- public void ModelInfo_HasPrimaryKeyShortTypeNameProperty_Net8()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("PrimaryKeyShortTypeName"));
- }
-
- [Fact]
- public void ModelInfo_HasPrimaryKeyTypeNameProperty_Net8()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("PrimaryKeyTypeName"));
- }
-
- [Fact]
- public void ModelInfo_ComputedProperties_WorkCorrectly_Net8()
- {
- var modelInfo = new ModelInfo { ModelTypeName = "product" };
- Assert.Equal("Product", modelInfo.ModelTypeNameCapitalized);
- Assert.Equal("products", modelInfo.ModelTypePluralName);
- Assert.Equal("product", modelInfo.ModelVariable);
- }
-
- #endregion
-
- #region PackageConstants — EF
-
- [Fact]
- public void PackageConstants_SqlServer_HasCorrectKey_Net8()
- {
- Assert.Equal("sqlserver-efcore", PackageConstants.EfConstants.SqlServer);
- }
-
- [Fact]
- public void PackageConstants_SQLite_HasCorrectKey_Net8()
- {
- Assert.Equal("sqlite-efcore", PackageConstants.EfConstants.SQLite);
- }
-
- [Fact]
- public void PackageConstants_CosmosDb_HasCorrectKey_Net8()
- {
- Assert.Equal("cosmos-efcore", PackageConstants.EfConstants.CosmosDb);
- }
-
- [Fact]
- public void PackageConstants_Postgres_HasCorrectKey_Net8()
- {
- Assert.Equal("npgsql-efcore", PackageConstants.EfConstants.Postgres);
- }
-
- [Fact]
- public void PackageConstants_EfCorePackage_HasCorrectName_Net8()
- {
- Assert.Equal("Microsoft.EntityFrameworkCore", PackageConstants.EfConstants.EfCorePackage.Name);
- }
-
- [Fact]
- public void PackageConstants_EfCorePackage_RequiresVersion_Net8()
- {
- Assert.True(PackageConstants.EfConstants.EfCorePackage.IsVersionRequired);
- }
-
- [Fact]
- public void PackageConstants_EfCoreToolsPackage_HasCorrectName_Net8()
- {
- Assert.Equal("Microsoft.EntityFrameworkCore.Tools", PackageConstants.EfConstants.EfCoreToolsPackage.Name);
- }
-
- [Fact]
- public void PackageConstants_EfCoreToolsPackage_RequiresVersion_Net8()
- {
- Assert.True(PackageConstants.EfConstants.EfCoreToolsPackage.IsVersionRequired);
- }
-
- [Fact]
- public void PackageConstants_SqlServerPackage_HasCorrectName_Net8()
- {
- Assert.Equal("Microsoft.EntityFrameworkCore.SqlServer", PackageConstants.EfConstants.SqlServerPackage.Name);
- }
-
- [Fact]
- public void PackageConstants_SqlitePackage_HasCorrectName_Net8()
- {
- Assert.Equal("Microsoft.EntityFrameworkCore.Sqlite", PackageConstants.EfConstants.SqlitePackage.Name);
- }
-
- [Fact]
- public void PackageConstants_CosmosPackage_HasCorrectName_Net8()
- {
- Assert.Equal("Microsoft.EntityFrameworkCore.Cosmos", PackageConstants.EfConstants.CosmosPackage.Name);
- }
-
- [Fact]
- public void PackageConstants_PostgresPackage_HasCorrectName_Net8()
- {
- Assert.Equal("Npgsql.EntityFrameworkCore.PostgreSQL", PackageConstants.EfConstants.PostgresPackage.Name);
- }
-
- [Fact]
- public void PackageConstants_EfPackagesDict_Contains4Providers_Net8()
- {
- Assert.Equal(4, PackageConstants.EfConstants.EfPackagesDict.Count);
- }
-
- [Fact]
- public void PackageConstants_EfPackagesDict_ContainsSqlServer_Net8()
- {
- Assert.True(PackageConstants.EfConstants.EfPackagesDict.ContainsKey(PackageConstants.EfConstants.SqlServer));
- }
-
- [Fact]
- public void PackageConstants_EfPackagesDict_ContainsSQLite_Net8()
- {
- Assert.True(PackageConstants.EfConstants.EfPackagesDict.ContainsKey(PackageConstants.EfConstants.SQLite));
- }
-
- [Fact]
- public void PackageConstants_EfPackagesDict_ContainsCosmosDb_Net8()
- {
- Assert.True(PackageConstants.EfConstants.EfPackagesDict.ContainsKey(PackageConstants.EfConstants.CosmosDb));
- }
-
- [Fact]
- public void PackageConstants_EfPackagesDict_ContainsPostgres_Net8()
- {
- Assert.True(PackageConstants.EfConstants.EfPackagesDict.ContainsKey(PackageConstants.EfConstants.Postgres));
- }
-
- [Fact]
- public void PackageConstants_ConnectionStringVariableName_IsCorrect_Net8()
- {
- Assert.Equal("connectionString", PackageConstants.EfConstants.ConnectionStringVariableName);
- }
-
- #endregion
-
- #region UseDatabaseMethods
-
- [Fact]
- public void UseDatabaseMethods_SqlServer_UseSqlServer_Net8()
- {
- Assert.True(PackageConstants.EfConstants.UseDatabaseMethods.ContainsKey(PackageConstants.EfConstants.SqlServer));
- Assert.Equal("UseSqlServer", PackageConstants.EfConstants.UseDatabaseMethods[PackageConstants.EfConstants.SqlServer]);
- }
-
- [Fact]
- public void UseDatabaseMethods_SQLite_UseSqlite_Net8()
- {
- Assert.True(PackageConstants.EfConstants.UseDatabaseMethods.ContainsKey(PackageConstants.EfConstants.SQLite));
- Assert.Equal("UseSqlite", PackageConstants.EfConstants.UseDatabaseMethods[PackageConstants.EfConstants.SQLite]);
- }
-
- [Fact]
- public void UseDatabaseMethods_Postgres_UseNpgsql_Net8()
- {
- Assert.True(PackageConstants.EfConstants.UseDatabaseMethods.ContainsKey(PackageConstants.EfConstants.Postgres));
- Assert.Equal("UseNpgsql", PackageConstants.EfConstants.UseDatabaseMethods[PackageConstants.EfConstants.Postgres]);
- }
-
- [Fact]
- public void UseDatabaseMethods_CosmosDb_UseCosmos_Net8()
- {
- Assert.True(PackageConstants.EfConstants.UseDatabaseMethods.ContainsKey(PackageConstants.EfConstants.CosmosDb));
- Assert.Equal("UseCosmos", PackageConstants.EfConstants.UseDatabaseMethods[PackageConstants.EfConstants.CosmosDb]);
- }
-
- #endregion
-
- #region Template Folder Verification — Net8 (.cshtml format)
-
- [Fact]
- public void Net8TemplateFolderContainsApiControllerWithContextTemplate_Net8()
- {
- var assembly = typeof(EfControllerHelper).Assembly;
- string basePath = Path.GetDirectoryName(assembly.Location)!;
- string templatePath = Path.Combine(basePath, "Templates", TargetFramework, "EfController", "ApiControllerWithContext.cshtml");
-
- if (File.Exists(templatePath))
- {
- string content = File.ReadAllText(templatePath);
- Assert.NotEmpty(content);
- }
- else
- {
- // Template may be embedded or packed from net9.0 at build time; verify source template types exist in assembly
- Assert.True(true, "Legacy .cshtml template expected packed from net9.0 at build time");
- }
- }
-
- [Fact]
- public void Net8TemplateFolderContainsMvcControllerWithContextTemplate_Net8()
- {
- var assembly = typeof(EfControllerHelper).Assembly;
- string basePath = Path.GetDirectoryName(assembly.Location)!;
- string templatePath = Path.Combine(basePath, "Templates", TargetFramework, "EfController", "MvcControllerWithContext.cshtml");
-
- if (File.Exists(templatePath))
- {
- string content = File.ReadAllText(templatePath);
- Assert.NotEmpty(content);
- }
- else
- {
- Assert.True(true, "Legacy .cshtml template expected packed from net9.0 at build time");
- }
- }
-
- #endregion
-
- #region EfControllerHelper Template Type Resolution
-
- [Fact]
- public void EfControllerHelper_TemplateTypes_AreResolvableFromAssembly_Net8()
- {
- // EfControllerHelper.GetCrudControllerType maps to Templates.net10.EfController types
- var assembly = typeof(EfControllerHelper).Assembly;
- var allTypes = assembly.GetTypes();
- var efControllerTypes = allTypes.Where(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.EfController")).ToList();
-
- Assert.True(efControllerTypes.Count > 0, "Expected EfController template types in assembly");
- }
-
- [Fact]
- public void EfControllerHelper_ApiEfController_TemplateTypeExists_Net8()
- {
- var assembly = typeof(EfControllerHelper).Assembly;
- var allTypes = assembly.GetTypes();
- var apiType = allTypes.FirstOrDefault(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.EfController") &&
- t.Name.Equals("ApiEfController", StringComparison.OrdinalIgnoreCase));
-
- Assert.NotNull(apiType);
- }
-
- [Fact]
- public void EfControllerHelper_MvcEfController_TemplateTypeExists_Net8()
- {
- var assembly = typeof(EfControllerHelper).Assembly;
- var allTypes = assembly.GetTypes();
- var mvcType = allTypes.FirstOrDefault(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.EfController") &&
- t.Name.Equals("MvcEfController", StringComparison.OrdinalIgnoreCase));
-
- Assert.NotNull(mvcType);
- }
-
- [Fact]
- public void EfControllerHelper_ThrowsWhenProjectInfoNull_Net8()
- {
- var model = new EfControllerModel
- {
- ControllerType = "API",
- ControllerName = "ProductsController",
- ControllerOutputPath = "Controllers",
- DbContextInfo = new DbContextInfo { DbContextClassName = "AppDbContext", EfScenario = true },
- ModelInfo = new ModelInfo { ModelTypeName = "Product" },
- ProjectInfo = new ProjectInfo(null)
- };
-
- Assert.Throws(() =>
- EfControllerHelper.GetEfControllerTemplatingProperty(model));
- }
-
- #endregion
-
- #region Code Modification Configs
-
- [Fact]
- public void Net8CodeModificationConfig_EfControllerChanges_Exists_Net8()
- {
- // For net8.0, the efControllerChanges.json is packed from net9.0 at build time
- // The code currently hardcodes net11.0 for the targetFrameworkFolder
- var assembly = typeof(EfControllerHelper).Assembly;
- string basePath = Path.GetDirectoryName(assembly.Location)!;
- // Check the net11.0 path since that's what the code actually uses
- string configPath = Path.Combine(basePath, "Templates", "net11.0", "CodeModificationConfigs", "efControllerChanges.json");
-
- if (File.Exists(configPath))
- {
- string content = File.ReadAllText(configPath);
- Assert.Contains("Program.cs", content);
- }
- else
- {
- Assert.True(true, "Config file expected embedded in assembly");
- }
- }
-
- #endregion
-
- #region Pipeline Step Sequence
-
- [Fact]
- public void ApiControllerCrudPipeline_DefinesCorrectStepSequence_Net8()
- {
- // API Controller CRUD pipeline: ValidateEfControllerStep → WithEfControllerAddPackagesStep → WithDbContextStep
- // → WithAspNetConnectionStringStep → WithEfControllerTextTemplatingStep → WithEfControllerCodeChangeStep
-
- // Verify key step types exist
- Assert.NotNull(typeof(ValidateEfControllerStep));
-
- // All key steps are classes
- Assert.True(typeof(ValidateEfControllerStep).IsClass);
+ protected override string TargetFramework => "net8.0";
+ protected override string TestClassName => nameof(ApiControllerNet8IntegrationTests);
+
+ [Fact]
+ public async Task Scaffold_ApiControllerCrud_Net8_CliInvocation()
+ {
+ // Arrange — set up project with Program.cs and a model class
+ File.WriteAllText(_testProjectPath, ProjectContent);
+ File.WriteAllText(Path.Combine(_testProjectDir, "Program.cs"), ScaffoldCliHelper.GetMinimalProgramCs());
+ var modelsDir = Path.Combine(_testProjectDir, "Models");
+ Directory.CreateDirectory(modelsDir);
+ File.WriteAllText(Path.Combine(modelsDir, "TestModel.cs"), ScaffoldCliHelper.GetModelClassContent("TestProject", "TestModel"));
+
+ // Verify project builds before scaffolding
+ var (beforeExitCode, _, beforeError) = await RunBuildAsync(_testProjectDir);
+ Assert.True(beforeExitCode == 0, $"Project should build before scaffolding. Error: {beforeError}");
+
+ // Act — invoke CLI: dotnet scaffold aspnet apicontroller-crud
+ var (cliExitCode, cliOutput, cliError) = await ScaffoldCliHelper.RunScaffoldAsync(
+ TargetFramework,
+ "apicontroller-crud",
+ "--project", _testProjectPath,
+ "--model", "TestModel",
+ "--controller", "TestApiController",
+ "--dataContext", "TestDbContext",
+ "--dbProvider", "sqlite-efcore");
+ Assert.True(cliExitCode == 0, $"CLI scaffold should succeed.\nOutput: {cliOutput}\nError: {cliError}");
+
+ // Assert — expected files were created
+ Assert.True(File.Exists(Path.Combine(_testProjectDir, "Controllers", "TestApiController.cs")),
+ "Controller file 'Controllers/TestApiController.cs' should be created.");
+ Assert.True(File.Exists(Path.Combine(_testProjectDir, "Data", "TestDbContext.cs")),
+ "DbContext file 'Data/TestDbContext.cs' should be created.");
+ var programContent = File.ReadAllText(Path.Combine(_testProjectDir, "Program.cs"));
+ Assert.Contains("TestDbContext", programContent);
+
+ // Assert — no NuGet errors and project builds after scaffolding
+ Assert.False(cliOutput.Contains("error: NU"),
+ $"Scaffolding should not produce NuGet errors for {TargetFramework}.\nOutput: {cliOutput}");
+ var (afterExitCode, _, afterError) = await RunBuildAsync(_testProjectDir);
+ Assert.True(afterExitCode == 0, $"Project should still build after scaffolding. Error: {afterError}");
}
-
- [Fact]
- public void MvcControllerCrudPipeline_HasAdditionalMvcViewsStep_Net8()
- {
- // MVC Controller CRUD pipeline adds WithMvcViewsStep() on top of API pipeline
- // WithMvcViewsStep adds: ValidateViewsStep, WrappedTextTemplatingStep, AddFileStep
- var extensionType = typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions);
- var method = extensionType.GetMethod("WithMvcViewsStep", BindingFlags.Public | BindingFlags.Static);
- Assert.NotNull(method);
- }
-
- [Fact]
- public void EntraIdPipeline_AllKeyStepsInheritFromScaffoldStep_Net8()
- {
- Assert.True(typeof(ValidateEfControllerStep).IsAssignableTo(typeof(ScaffoldStep)));
- }
-
- [Fact]
- public void EfControllerPipeline_AllKeyStepsAreInScaffoldStepsNamespace_Net8()
- {
- string expectedNs = "Microsoft.DotNet.Tools.Scaffold.AspNet.ScaffoldSteps";
- Assert.Equal(expectedNs, typeof(ValidateEfControllerStep).Namespace);
- }
-
- #endregion
-
- #region Builder Extensions
-
- [Fact]
- public void EfControllerBuilderExtensions_WithEfControllerTextTemplatingStep_Exists_Net8()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions);
- var method = extensionType.GetMethod("WithEfControllerTextTemplatingStep", BindingFlags.Public | BindingFlags.Static);
- Assert.NotNull(method);
- }
-
- [Fact]
- public void EfControllerBuilderExtensions_WithEfControllerAddPackagesStep_Exists_Net8()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions);
- var method = extensionType.GetMethod("WithEfControllerAddPackagesStep", BindingFlags.Public | BindingFlags.Static);
- Assert.NotNull(method);
- }
-
- [Fact]
- public void EfControllerBuilderExtensions_WithEfControllerCodeChangeStep_Exists_Net8()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions);
- var method = extensionType.GetMethod("WithEfControllerCodeChangeStep", BindingFlags.Public | BindingFlags.Static);
- Assert.NotNull(method);
- }
-
- [Fact]
- public void EfControllerBuilderExtensions_WithMvcViewsStep_Exists_Net8()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions);
- var method = extensionType.GetMethod("WithMvcViewsStep", BindingFlags.Public | BindingFlags.Static);
- Assert.NotNull(method);
- }
-
- [Fact]
- public void EfControllerBuilderExtensions_Has4ExtensionMethods_Net8()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions);
- var methods = extensionType.GetMethods(BindingFlags.Public | BindingFlags.Static)
- .Where(m => m.GetParameters().Any(p => p.ParameterType == typeof(IScaffoldBuilder)))
- .ToList();
- // WithEfControllerTextTemplatingStep, WithEfControllerAddPackagesStep,
- // WithEfControllerCodeChangeStep, WithMvcViewsStep
- Assert.Equal(4, methods.Count);
- }
-
- [Fact]
- public void EfControllerBuilderExtensions_AllMethodsReturnIScaffoldBuilder_Net8()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions);
- var methods = extensionType.GetMethods(BindingFlags.Public | BindingFlags.Static)
- .Where(m => m.GetParameters().Any(p => p.ParameterType == typeof(IScaffoldBuilder)))
- .ToList();
-
- foreach (var method in methods)
- {
- Assert.Equal(typeof(IScaffoldBuilder), method.ReturnType);
- }
- }
-
- #endregion
-
- #region TFM Availability
-
- [Fact]
- public void ApiControllerCrud_IsAvailableForNet8_Net8()
- {
- // API category is available for all TFMs including Net8
- // (only "Aspire" and "Entra ID" are removed for Net8)
- Assert.Equal("API", AspnetStrings.Catagories.API);
- }
-
- [Fact]
- public void MvcControllerCrud_IsAvailableForNet8_Net8()
- {
- // MVC category is available for all TFMs including Net8
- Assert.Equal("MVC", AspnetStrings.Catagories.MVC);
- }
-
- [Fact]
- public void CommandInfoExtensions_IsCommandAnAspNetCommand_Exists_Net8()
- {
- var method = typeof(CommandInfoExtensions).GetMethod("IsCommandAnAspNetCommand");
- Assert.NotNull(method);
- }
-
- #endregion
-
- #region Cancellation Support
-
- [Fact]
- public async Task ValidateEfControllerStep_AcceptsCancellationToken_Net8()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext"
- };
-
- using var cts = new CancellationTokenSource();
- bool result = await step.ExecuteAsync(_context, cts.Token);
-
- Assert.False(result);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_ExecuteAsync_IsInherited_Net8()
- {
- var method = typeof(ValidateEfControllerStep).GetMethod("ExecuteAsync", new[] { typeof(ScaffolderContext), typeof(CancellationToken) });
- Assert.NotNull(method);
- Assert.True(method!.IsVirtual);
- }
-
- #endregion
-
- #region Scaffolder Registration Constants
-
- [Fact]
- public void ApiControllerCrud_UsesCorrectName_Net8()
- {
- Assert.Equal("apicontroller-crud", AspnetStrings.Api.ApiControllerCrud);
- }
-
- [Fact]
- public void ApiControllerCrud_UsesCorrectDisplayName_Net8()
- {
- Assert.Equal("API Controller with actions, using Entity Framework (CRUD)", AspnetStrings.Api.ApiControllerCrudDisplayName);
- }
-
- [Fact]
- public void ApiControllerCrud_UsesCorrectCategory_Net8()
- {
- Assert.Equal("API", AspnetStrings.Catagories.API);
- }
-
- [Fact]
- public void ApiControllerCrud_UsesCorrectDescription_Net8()
- {
- Assert.Equal("Create an API controller with REST actions to create, read, update, delete, and list entities", AspnetStrings.Api.ApiControllerCrudDescription);
- }
-
- [Fact]
- public void ApiControllerCrud_Has2Examples_Net8()
- {
- Assert.NotEmpty(AspnetStrings.Api.ApiControllerCrudExample1);
- Assert.NotEmpty(AspnetStrings.Api.ApiControllerCrudExample2);
- Assert.NotEmpty(AspnetStrings.Api.ApiControllerCrudExample1Description);
- Assert.NotEmpty(AspnetStrings.Api.ApiControllerCrudExample2Description);
- }
-
- [Fact]
- public void MvcControllerCrud_Has2Examples_Net8()
- {
- Assert.NotEmpty(AspnetStrings.MVC.ControllerCrudExample1);
- Assert.NotEmpty(AspnetStrings.MVC.ControllerCrudExample2);
- Assert.NotEmpty(AspnetStrings.MVC.ControllerCrudExample1Description);
- Assert.NotEmpty(AspnetStrings.MVC.ControllerCrudExample2Description);
- }
-
- #endregion
-
- #region Scaffolding Context Properties
-
- [Fact]
- public void ScaffolderContext_CanStoreEfControllerModel_Net8()
- {
- var model = new EfControllerModel
- {
- ControllerType = "API",
- ControllerName = "ProductsController",
- ControllerOutputPath = Path.Combine(_testProjectDir, "Controllers"),
- DbContextInfo = new DbContextInfo { DbContextClassName = "AppDbContext", EfScenario = true },
- ModelInfo = new ModelInfo { ModelTypeName = "Product" },
- ProjectInfo = new ProjectInfo(_testProjectPath)
- };
-
- _context.Properties.Add(nameof(EfControllerModel), model);
-
- Assert.True(_context.Properties.ContainsKey(nameof(EfControllerModel)));
- var retrieved = _context.Properties[nameof(EfControllerModel)] as EfControllerModel;
- Assert.NotNull(retrieved);
- Assert.Equal("API", retrieved!.ControllerType);
- Assert.Equal("ProductsController", retrieved.ControllerName);
- Assert.Equal("Product", retrieved.ModelInfo.ModelTypeName);
- Assert.True(retrieved.DbContextInfo.EfScenario);
- }
-
- [Fact]
- public void ScaffolderContext_CanStoreEfControllerSettings_Net8()
- {
- var settings = new EfControllerSettings
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer,
- Prerelease = false
- };
-
- _context.Properties.Add(nameof(EfControllerSettings), settings);
-
- Assert.True(_context.Properties.ContainsKey(nameof(EfControllerSettings)));
- var retrieved = _context.Properties[nameof(EfControllerSettings)] as EfControllerSettings;
- Assert.NotNull(retrieved);
- Assert.Equal(_testProjectPath, retrieved!.Project);
- Assert.Equal("API", retrieved.ControllerType);
- Assert.Equal("Product", retrieved.Model);
- }
-
- [Fact]
- public void ScaffolderContext_CanStoreCodeModifierProperties_Net8()
- {
- var codeModifierProperties = new Dictionary
- {
- { "DbContextName", "AppDbContext" },
- { "ConnectionStringName", "DefaultConnection" }
- };
-
- _context.Properties.Add(Scaffolding.Internal.Constants.StepConstants.CodeModifierProperties, codeModifierProperties);
-
- Assert.True(_context.Properties.ContainsKey(Scaffolding.Internal.Constants.StepConstants.CodeModifierProperties));
- var retrieved = _context.Properties[Scaffolding.Internal.Constants.StepConstants.CodeModifierProperties] as Dictionary;
- Assert.NotNull(retrieved);
- Assert.Equal(2, retrieved!.Count);
- }
-
- #endregion
-
- #region ControllerOutputPath Constant
-
- [Fact]
- public void ControllerCommandOutput_IsControllers_Net8()
- {
- Assert.Equal("Controllers", AspNetConstants.DotnetCommands.ControllerCommandOutput);
- }
-
- #endregion
-
- #region NewDbContext Constant
-
- [Fact]
- public void NewDbContext_HasCorrectValue_Net8()
- {
- Assert.Equal("NewDbContext", AspNetConstants.NewDbContext);
- }
-
- #endregion
-
- #region File Extensions
-
- [Fact]
- public void CSharpExtension_IsCorrect_Net8()
- {
- Assert.Equal(".cs", AspNetConstants.CSharpExtension);
- }
-
- #endregion
-
- #region Validation Combination Tests
-
- [Fact]
- public async Task ValidateEfControllerStep_NullProject_FailsValidation_Net8()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = null,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext"
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_NullModel_FailsValidation_Net8()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = null,
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext"
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_NullControllerName_FailsValidation_Net8()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = null,
- ControllerType = "API",
- DataContext = "AppDbContext"
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_NullControllerType_FailsValidation_Net8()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = null,
- DataContext = "AppDbContext"
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_NullDataContext_FailsValidation_Net8()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = null
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_AllFieldsEmpty_FailsValidation_Net8()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = string.Empty,
- Model = string.Empty,
- ControllerName = string.Empty,
- ControllerType = string.Empty,
- DataContext = string.Empty
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- #endregion
-
- #region Regression Guards
-
- [Fact]
- public void EfControllerModel_IsInModelsNamespace_Net8()
- {
- Assert.Equal("Microsoft.DotNet.Tools.Scaffold.AspNet.Models", typeof(EfControllerModel).Namespace);
- }
-
- [Fact]
- public void EfControllerSettings_IsInSettingsNamespace_Net8()
- {
- Assert.Equal("Microsoft.DotNet.Tools.Scaffold.AspNet.ScaffoldSteps.Settings", typeof(EfControllerSettings).Namespace);
- }
-
- [Fact]
- public void EfControllerHelper_IsInHelpersNamespace_Net8()
- {
- Assert.Equal("Microsoft.DotNet.Tools.Scaffold.AspNet.Helpers", typeof(EfControllerHelper).Namespace);
- }
-
- [Fact]
- public void ValidateEfControllerStep_IsInternal_Net8()
- {
- Assert.False(typeof(ValidateEfControllerStep).IsPublic);
- }
-
- [Fact]
- public void EfControllerModel_IsInternal_Net8()
- {
- Assert.False(typeof(EfControllerModel).IsPublic);
- }
-
- [Fact]
- public void EfControllerSettings_IsInternal_Net8()
- {
- Assert.False(typeof(EfControllerSettings).IsPublic);
- }
-
- [Fact]
- public void EfControllerScaffolderBuilderExtensions_IsInternal_Net8()
- {
- Assert.False(typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions).IsPublic);
- }
-
- [Fact]
- public void EfControllerHelper_IsInternal_Net8()
- {
- Assert.False(typeof(EfControllerHelper).IsPublic);
- }
-
- [Fact]
- public void EfControllerHelper_IsStatic_Net8()
- {
- Assert.True(typeof(EfControllerHelper).IsAbstract && typeof(EfControllerHelper).IsSealed);
- }
-
- [Fact]
- public void DbContextInfo_IsInternal_Net8()
- {
- Assert.False(typeof(DbContextInfo).IsPublic);
- }
-
- [Fact]
- public void ModelInfo_IsInternal_Net8()
- {
- Assert.False(typeof(ModelInfo).IsPublic);
- }
-
- #endregion
-
- #region API Controller Scaffolder — Non-CRUD Strings
-
- [Fact]
- public void ApiControllerNonCrud_Name_IsApiController_Net8()
- {
- Assert.Equal("apicontroller", AspnetStrings.Api.ApiController);
- }
-
- [Fact]
- public void ApiControllerNonCrud_DisplayName_Net8()
- {
- Assert.Equal("API Controller", AspnetStrings.Api.ApiControllerDisplayName);
- }
-
- [Fact]
- public void MvcControllerNonCrud_Name_IsMvcController_Net8()
- {
- Assert.Equal("mvccontroller", AspnetStrings.MVC.Controller);
- }
-
- [Fact]
- public void MvcControllerNonCrud_DisplayName_Net8()
- {
- Assert.Equal("MVC Controller", AspnetStrings.MVC.DisplayName);
- }
-
- #endregion
-
- #region ControllerType Values
-
- [Fact]
- public void ControllerType_APIValue_MatchesCategoryName_Net8()
- {
- // The pipeline sets ControllerType = AspnetStrings.Catagories.API (value "API")
- Assert.Equal("API", AspnetStrings.Catagories.API);
- }
-
- [Fact]
- public void ControllerType_MVCValue_MatchesCategoryName_Net8()
- {
- // The pipeline sets ControllerType = AspnetStrings.Catagories.MVC (value "MVC")
- Assert.Equal("MVC", AspnetStrings.Catagories.MVC);
- }
-
- #endregion
-
- #region TestTelemetryService Helper
-
- private class TestTelemetryService : ITelemetryService
- {
- public List<(string EventName, IReadOnlyDictionary Properties, IReadOnlyDictionary Measurements)> TrackedEvents { get; } = new();
-
- public void TrackEvent(string eventName, IReadOnlyDictionary properties, IReadOnlyDictionary measurements)
- {
- TrackedEvents.Add((eventName, properties, measurements));
- }
-
- public void Flush()
- {
- }
- }
-
- #endregion
}
diff --git a/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/ApiControllerNet9IntegrationTests.cs b/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/ApiControllerNet9IntegrationTests.cs
index 0ffc0adf2..68d608cd5 100644
--- a/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/ApiControllerNet9IntegrationTests.cs
+++ b/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/ApiControllerNet9IntegrationTests.cs
@@ -1,1752 +1,55 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System;
-using System.Collections.Generic;
using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Threading;
using System.Threading.Tasks;
-using Microsoft.DotNet.Scaffolding.Core.Builder;
-using Microsoft.DotNet.Scaffolding.Core.ComponentModel;
-using Microsoft.DotNet.Scaffolding.Core.Scaffolders;
-using Microsoft.DotNet.Scaffolding.Core.Steps;
-using Microsoft.DotNet.Scaffolding.Internal.Services;
-using Microsoft.DotNet.Scaffolding.Internal.Telemetry;
-using Microsoft.DotNet.Scaffolding.TextTemplating;
-using Microsoft.DotNet.Tools.Scaffold.AspNet;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.Commands;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.Common;
-using AspNetConstants = Microsoft.DotNet.Tools.Scaffold.AspNet.Common.Constants;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.Helpers;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.Models;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.ScaffoldSteps;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.ScaffoldSteps.Settings;
-using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Logging.Abstractions;
-using Moq;
+using Microsoft.DotNet.Tools.Scaffold.Tests.Helpers;
using Xunit;
namespace Microsoft.DotNet.Tools.Scaffold.Tests.AspNet.Integration.API;
-///
-/// Integration tests for the API Controller CRUD (apicontroller-crud) scaffolder targeting .NET 9.
-/// Validates scaffolder definition constants, ValidateEfControllerStep validation logic,
-/// EfControllerModel/EfControllerSettings/EfWithModelStepSettings/BaseSettings properties,
-/// EfControllerHelper template resolution, template folder verification, code modification configs,
-/// package constants, pipeline registration, step dependencies, telemetry tracking,
-/// TFM availability, builder extensions, and database provider support.
-/// The API Controller CRUD scaffolder is available for all supported TFMs including .NET 9.
-/// .NET 9 EfController templates use .tt text template format (ApiEfController.tt, MvcEfController.tt)
-/// compiled to the Templates.EfController namespace.
-///
-public class ApiControllerNet9IntegrationTests : IDisposable
+public class ApiControllerNet9IntegrationTests : ApiControllerIntegrationTestsBase
{
- private const string TargetFramework = "net9.0";
- private readonly string _testDirectory;
- private readonly string _testProjectDir;
- private readonly string _testProjectPath;
- private readonly Mock _mockFileSystem;
- private readonly TestTelemetryService _testTelemetryService;
- private readonly Mock _mockScaffolder;
- private readonly ScaffolderContext _context;
-
- public ApiControllerNet9IntegrationTests()
- {
- _testDirectory = Path.Combine(Path.GetTempPath(), "ApiControllerNet9IntegrationTests", Guid.NewGuid().ToString());
- _testProjectDir = Path.Combine(_testDirectory, "TestProject");
- _testProjectPath = Path.Combine(_testProjectDir, "TestProject.csproj");
- Directory.CreateDirectory(_testProjectDir);
-
- _mockFileSystem = new Mock();
- _testTelemetryService = new TestTelemetryService();
- _mockScaffolder = new Mock();
- _mockScaffolder.Setup(s => s.DisplayName).Returns(AspnetStrings.Api.ApiControllerCrudDisplayName);
- _mockScaffolder.Setup(s => s.Name).Returns(AspnetStrings.Api.ApiControllerCrud);
- _context = new ScaffolderContext(_mockScaffolder.Object);
- }
-
- public void Dispose()
- {
- if (Directory.Exists(_testDirectory))
- {
- try { Directory.Delete(_testDirectory, recursive: true); }
- catch { /* best-effort cleanup */ }
- }
- }
-
- #region Constants & Scaffolder Definition — API Controller CRUD
-
- [Fact]
- public void ScaffolderName_IsApiControllerCrud_Net9()
- {
- Assert.Equal("apicontroller-crud", AspnetStrings.Api.ApiControllerCrud);
- }
-
- [Fact]
- public void ScaffolderDisplayName_IsApiControllerCrudDisplayName_Net9()
- {
- Assert.Equal("API Controller with actions, using Entity Framework (CRUD)", AspnetStrings.Api.ApiControllerCrudDisplayName);
- }
-
- [Fact]
- public void ScaffolderDescription_IsApiControllerCrudDescription_Net9()
- {
- Assert.Equal("Create an API controller with REST actions to create, read, update, delete, and list entities", AspnetStrings.Api.ApiControllerCrudDescription);
- }
-
- [Fact]
- public void ScaffolderCategory_IsAPI_Net9()
- {
- Assert.Equal("API", AspnetStrings.Catagories.API);
- }
-
- [Fact]
- public void ScaffolderExample1_ContainsApiControllerCrudCommand_Net9()
- {
- Assert.Contains("apicontroller-crud", AspnetStrings.Api.ApiControllerCrudExample1);
- }
-
- [Fact]
- public void ScaffolderExample1_ContainsRequiredOptions_Net9()
- {
- Assert.Contains("--project", AspnetStrings.Api.ApiControllerCrudExample1);
- Assert.Contains("--model", AspnetStrings.Api.ApiControllerCrudExample1);
- Assert.Contains("--controller-name", AspnetStrings.Api.ApiControllerCrudExample1);
- Assert.Contains("--data-context", AspnetStrings.Api.ApiControllerCrudExample1);
- Assert.Contains("--database-provider", AspnetStrings.Api.ApiControllerCrudExample1);
- }
-
- [Fact]
- public void ScaffolderExample2_ContainsApiControllerCrudCommand_Net9()
- {
- Assert.Contains("apicontroller-crud", AspnetStrings.Api.ApiControllerCrudExample2);
- }
-
- [Fact]
- public void ScaffolderExample2_ContainsPrerelease_Net9()
- {
- Assert.Contains("--prerelease", AspnetStrings.Api.ApiControllerCrudExample2);
- }
-
- [Fact]
- public void ScaffolderExample1Description_MentionsCrudOperations_Net9()
- {
- Assert.Contains("CRUD", AspnetStrings.Api.ApiControllerCrudExample1Description);
- }
-
- [Fact]
- public void ScaffolderExample2Description_MentionsPostgreSQL_Net9()
- {
- Assert.Contains("PostgreSQL", AspnetStrings.Api.ApiControllerCrudExample2Description);
- }
-
- #endregion
-
- #region Constants & Scaffolder Definition — MVC Controller CRUD
-
- [Fact]
- public void MVC_ScaffolderName_IsMvcControllerCrud_Net9()
- {
- Assert.Equal("mvccontroller-crud", AspnetStrings.MVC.ControllerCrud);
- }
-
- [Fact]
- public void MVC_ScaffolderDisplayName_IsMvcControllerCrudDisplayName_Net9()
- {
- Assert.Equal("MVC Controller with views, using Entity Framework (CRUD)", AspnetStrings.MVC.CrudDisplayName);
- }
-
- [Fact]
- public void MVC_ScaffolderDescription_IsMvcControllerCrudDescription_Net9()
- {
- Assert.Equal("Create a MVC controller with read/write actions and views using Entity Framework", AspnetStrings.MVC.CrudDescription);
- }
-
- [Fact]
- public void MVC_ScaffolderCategory_IsMVC_Net9()
- {
- Assert.Equal("MVC", AspnetStrings.Catagories.MVC);
- }
-
- [Fact]
- public void MVC_ScaffolderExample1_ContainsMvcControllerCrudCommand_Net9()
- {
- Assert.Contains("mvccontroller-crud", AspnetStrings.MVC.ControllerCrudExample1);
- }
-
- [Fact]
- public void MVC_ScaffolderExample1_ContainsViewsOption_Net9()
- {
- Assert.Contains("--views", AspnetStrings.MVC.ControllerCrudExample1);
- }
-
- #endregion
-
- #region CLI Options
-
- [Fact]
- public void CliOption_ProjectOption_IsCorrect_Net9()
- {
- Assert.Equal("--project", AspNetConstants.CliOptions.ProjectCliOption);
- }
-
- [Fact]
- public void CliOption_ModelOption_IsCorrect_Net9()
- {
- Assert.Equal("--model", AspNetConstants.CliOptions.ModelCliOption);
- }
-
- [Fact]
- public void CliOption_DataContextOption_IsCorrect_Net9()
- {
- Assert.Equal("--dataContext", AspNetConstants.CliOptions.DataContextOption);
- }
-
- [Fact]
- public void CliOption_DbProviderOption_IsCorrect_Net9()
- {
- Assert.Equal("--dbProvider", AspNetConstants.CliOptions.DbProviderOption);
- }
-
- [Fact]
- public void CliOption_ControllerNameOption_IsCorrect_Net9()
- {
- Assert.Equal("--controller", AspNetConstants.CliOptions.ControllerNameOption);
- }
-
- [Fact]
- public void CliOption_PrereleaseOption_IsCorrect_Net9()
- {
- Assert.Equal("--prerelease", AspNetConstants.CliOptions.PrereleaseCliOption);
- }
-
- [Fact]
- public void CliOption_ViewsOption_IsCorrect_Net9()
- {
- Assert.Equal("--views", AspNetConstants.CliOptions.ViewsOption);
- }
-
- #endregion
-
- #region AspNetOptions for EfController
-
- [Fact]
- public void AspNetOptions_HasModelNameProperty_Net9()
- {
- var prop = typeof(AspNetOptions).GetProperty("ModelName");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasControllerNameProperty_Net9()
- {
- var prop = typeof(AspNetOptions).GetProperty("ControllerName");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasDataContextClassRequiredProperty_Net9()
- {
- var prop = typeof(AspNetOptions).GetProperty("DataContextClassRequired");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasDatabaseProviderRequiredProperty_Net9()
- {
- var prop = typeof(AspNetOptions).GetProperty("DatabaseProviderRequired");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasPrereleaseProperty_Net9()
- {
- var prop = typeof(AspNetOptions).GetProperty("Prerelease");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasViewsProperty_Net9()
- {
- var prop = typeof(AspNetOptions).GetProperty("Views");
- Assert.NotNull(prop);
- }
-
- #endregion
-
- #region ValidateEfControllerStep — Properties and Construction
-
- [Fact]
- public void ValidateEfControllerStep_IsScaffoldStep_Net9()
- {
- Assert.True(typeof(ValidateEfControllerStep).IsAssignableTo(typeof(ScaffoldStep)));
- }
-
- [Fact]
- public void ValidateEfControllerStep_HasProjectProperty_Net9()
- {
- Assert.NotNull(typeof(ValidateEfControllerStep).GetProperty("Project"));
- }
-
- [Fact]
- public void ValidateEfControllerStep_HasPrereleaseProperty_Net9()
- {
- Assert.NotNull(typeof(ValidateEfControllerStep).GetProperty("Prerelease"));
- }
-
- [Fact]
- public void ValidateEfControllerStep_HasDatabaseProviderProperty_Net9()
- {
- Assert.NotNull(typeof(ValidateEfControllerStep).GetProperty("DatabaseProvider"));
- }
-
- [Fact]
- public void ValidateEfControllerStep_HasDataContextProperty_Net9()
- {
- Assert.NotNull(typeof(ValidateEfControllerStep).GetProperty("DataContext"));
- }
-
- [Fact]
- public void ValidateEfControllerStep_HasModelProperty_Net9()
- {
- Assert.NotNull(typeof(ValidateEfControllerStep).GetProperty("Model"));
- }
-
- [Fact]
- public void ValidateEfControllerStep_HasControllerNameProperty_Net9()
- {
- Assert.NotNull(typeof(ValidateEfControllerStep).GetProperty("ControllerName"));
- }
-
- [Fact]
- public void ValidateEfControllerStep_HasControllerTypeProperty_Net9()
- {
- Assert.NotNull(typeof(ValidateEfControllerStep).GetProperty("ControllerType"));
- }
-
- [Fact]
- public void ValidateEfControllerStep_Has7Properties_Net9()
- {
- // Project, Prerelease, DatabaseProvider, DataContext, Model, ControllerName, ControllerType
- var props = typeof(ValidateEfControllerStep).GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
- Assert.Equal(7, props.Length);
- }
-
- [Fact]
- public void ValidateEfControllerStep_Constructor_RequiresFileSystem_Net9()
- {
- var ctor = typeof(ValidateEfControllerStep).GetConstructors().First();
- var parameters = ctor.GetParameters();
- Assert.Contains(parameters, p => p.ParameterType == typeof(IFileSystem));
- }
-
- [Fact]
- public void ValidateEfControllerStep_Constructor_RequiresLogger_Net9()
- {
- var ctor = typeof(ValidateEfControllerStep).GetConstructors().First();
- var parameters = ctor.GetParameters();
- Assert.Contains(parameters, p => p.ParameterType == typeof(ILogger));
- }
-
- [Fact]
- public void ValidateEfControllerStep_Constructor_RequiresTelemetryService_Net9()
- {
- var ctor = typeof(ValidateEfControllerStep).GetConstructors().First();
- var parameters = ctor.GetParameters();
- Assert.Contains(parameters, p => p.ParameterType == typeof(ITelemetryService));
- }
-
- [Fact]
- public void ValidateEfControllerStep_Constructor_Has3Parameters_Net9()
- {
- var ctor = typeof(ValidateEfControllerStep).GetConstructors().First();
- Assert.Equal(3, ctor.GetParameters().Length);
- }
-
- #endregion
-
- #region ValidateEfControllerStep — Validation Logic
-
- [Fact]
- public async Task ValidateEfControllerStep_FailsWhenProjectMissing_Net9()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_FailsWhenProjectFileDoesNotExist_Net9()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_FailsWhenModelMissing_Net9()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = string.Empty,
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_FailsWhenControllerNameMissing_Net9()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = string.Empty,
- ControllerType = "API",
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_FailsWhenControllerTypeMissing_Net9()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = string.Empty,
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_FailsWhenDataContextMissing_Net9()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = string.Empty,
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_StepProperties_AreSetCorrectly_Net9()
- {
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer,
- Prerelease = true
- };
-
- Assert.Equal(_testProjectPath, step.Project);
- Assert.Equal("Product", step.Model);
- Assert.Equal("ProductsController", step.ControllerName);
- Assert.Equal("API", step.ControllerType);
- Assert.Equal("AppDbContext", step.DataContext);
- Assert.Equal(PackageConstants.EfConstants.SqlServer, step.DatabaseProvider);
- Assert.True(step.Prerelease);
- }
-
- #endregion
-
- #region Telemetry
-
- [Fact]
- public async Task TelemetryEventName_IsValidateEfControllerStepEvent_Net9()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext"
- };
-
- await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.Single(_testTelemetryService.TrackedEvents);
- Assert.Equal("ValidateEfControllerStepEvent", _testTelemetryService.TrackedEvents[0].EventName);
- }
-
- [Fact]
- public async Task TelemetryEvent_ContainsScaffolderNameProperty_Net9()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext"
- };
-
- await step.ExecuteAsync(_context, CancellationToken.None);
-
- var props = _testTelemetryService.TrackedEvents[0].Properties;
- Assert.True(props.ContainsKey("ScaffolderName"));
- Assert.Equal("API Controller with actions, using Entity Framework (CRUD)", props["ScaffolderName"]);
- }
-
- [Fact]
- public async Task TelemetryEvent_ContainsResultProperty_OnFailure_Net9()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext"
- };
-
- await step.ExecuteAsync(_context, CancellationToken.None);
-
- var props = _testTelemetryService.TrackedEvents[0].Properties;
- Assert.True(props.ContainsKey("Result"));
- Assert.Equal("Failure", props["Result"]);
- }
-
- [Fact]
- public async Task TelemetryEvent_SingleEventPerValidation_Net9()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = string.Empty,
- Model = string.Empty,
- ControllerName = string.Empty,
- ControllerType = string.Empty,
- DataContext = string.Empty
- };
-
- await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- #endregion
-
- #region EfControllerModel Properties
-
- [Fact]
- public void EfControllerModel_HasControllerTypeProperty_Net9()
- {
- Assert.NotNull(typeof(EfControllerModel).GetProperty("ControllerType"));
- }
-
- [Fact]
- public void EfControllerModel_HasControllerNameProperty_Net9()
- {
- Assert.NotNull(typeof(EfControllerModel).GetProperty("ControllerName"));
- }
-
- [Fact]
- public void EfControllerModel_HasControllerOutputPathProperty_Net9()
- {
- Assert.NotNull(typeof(EfControllerModel).GetProperty("ControllerOutputPath"));
- }
-
- [Fact]
- public void EfControllerModel_HasDbContextInfoProperty_Net9()
- {
- Assert.NotNull(typeof(EfControllerModel).GetProperty("DbContextInfo"));
- }
-
- [Fact]
- public void EfControllerModel_HasModelInfoProperty_Net9()
- {
- Assert.NotNull(typeof(EfControllerModel).GetProperty("ModelInfo"));
- }
-
- [Fact]
- public void EfControllerModel_HasProjectInfoProperty_Net9()
- {
- Assert.NotNull(typeof(EfControllerModel).GetProperty("ProjectInfo"));
- }
-
- [Fact]
- public void EfControllerModel_Has6Properties_Net9()
- {
- var props = typeof(EfControllerModel).GetProperties(BindingFlags.Public | BindingFlags.Instance);
- Assert.Equal(6, props.Length);
- }
-
- #endregion
-
- #region EfControllerSettings Properties
-
- [Fact]
- public void EfControllerSettings_HasControllerTypeProperty_Net9()
- {
- Assert.NotNull(typeof(EfControllerSettings).GetProperty("ControllerType"));
- }
-
- [Fact]
- public void EfControllerSettings_HasControllerNameProperty_Net9()
- {
- Assert.NotNull(typeof(EfControllerSettings).GetProperty("ControllerName"));
- }
-
- [Fact]
- public void EfControllerSettings_InheritsFromEfWithModelStepSettings_Net9()
- {
- Assert.True(typeof(EfControllerSettings).IsAssignableTo(typeof(EfWithModelStepSettings)));
- }
-
- [Fact]
- public void EfControllerSettings_HasProjectProperty_Net9()
- {
- // Inherited from BaseSettings
- Assert.NotNull(typeof(EfControllerSettings).GetProperty("Project"));
- }
-
- [Fact]
- public void EfControllerSettings_HasModelProperty_Net9()
- {
- // Inherited from EfWithModelStepSettings
- Assert.NotNull(typeof(EfControllerSettings).GetProperty("Model"));
- }
-
- [Fact]
- public void EfControllerSettings_HasDataContextProperty_Net9()
- {
- // Inherited from EfWithModelStepSettings
- Assert.NotNull(typeof(EfControllerSettings).GetProperty("DataContext"));
- }
-
- [Fact]
- public void EfControllerSettings_HasDatabaseProviderProperty_Net9()
- {
- // Inherited from EfWithModelStepSettings
- Assert.NotNull(typeof(EfControllerSettings).GetProperty("DatabaseProvider"));
- }
-
- [Fact]
- public void EfControllerSettings_HasPrereleaseProperty_Net9()
- {
- // Inherited from EfWithModelStepSettings
- Assert.NotNull(typeof(EfControllerSettings).GetProperty("Prerelease"));
- }
-
- #endregion
-
- #region EfWithModelStepSettings Properties
-
- [Fact]
- public void EfWithModelStepSettings_InheritsFromBaseSettings_Net9()
- {
- Assert.True(typeof(EfWithModelStepSettings).IsAssignableTo(typeof(BaseSettings)));
- }
-
- [Fact]
- public void EfWithModelStepSettings_HasDatabaseProviderProperty_Net9()
- {
- Assert.NotNull(typeof(EfWithModelStepSettings).GetProperty("DatabaseProvider"));
- }
-
- [Fact]
- public void EfWithModelStepSettings_HasDataContextProperty_Net9()
- {
- Assert.NotNull(typeof(EfWithModelStepSettings).GetProperty("DataContext"));
- }
-
- [Fact]
- public void EfWithModelStepSettings_HasModelProperty_Net9()
- {
- Assert.NotNull(typeof(EfWithModelStepSettings).GetProperty("Model"));
- }
-
- [Fact]
- public void EfWithModelStepSettings_HasPrereleaseProperty_Net9()
- {
- Assert.NotNull(typeof(EfWithModelStepSettings).GetProperty("Prerelease"));
- }
-
- #endregion
-
- #region BaseSettings Properties
-
- [Fact]
- public void BaseSettings_HasProjectProperty_Net9()
- {
- Assert.NotNull(typeof(BaseSettings).GetProperty("Project"));
- }
-
- [Fact]
- public void BaseSettings_IsInternal_Net9()
- {
- Assert.False(typeof(BaseSettings).IsPublic);
- }
-
- #endregion
-
- #region DbContextInfo Properties
-
- [Fact]
- public void DbContextInfo_HasDbContextClassNameProperty_Net9()
- {
- Assert.NotNull(typeof(DbContextInfo).GetProperty("DbContextClassName"));
- }
-
- [Fact]
- public void DbContextInfo_HasDbContextClassPathProperty_Net9()
- {
- Assert.NotNull(typeof(DbContextInfo).GetProperty("DbContextClassPath"));
- }
-
- [Fact]
- public void DbContextInfo_HasDbContextNamespaceProperty_Net9()
- {
- Assert.NotNull(typeof(DbContextInfo).GetProperty("DbContextNamespace"));
- }
-
- [Fact]
- public void DbContextInfo_HasDatabaseProviderProperty_Net9()
- {
- Assert.NotNull(typeof(DbContextInfo).GetProperty("DatabaseProvider"));
- }
-
- [Fact]
- public void DbContextInfo_HasEfScenarioProperty_Net9()
- {
- Assert.NotNull(typeof(DbContextInfo).GetProperty("EfScenario"));
- }
-
- [Fact]
- public void DbContextInfo_DefaultEfScenario_IsFalse_Net9()
- {
- var info = new DbContextInfo();
- Assert.False(info.EfScenario);
- }
-
- #endregion
-
- #region ModelInfo Properties
-
- [Fact]
- public void ModelInfo_HasModelTypeNameProperty_Net9()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("ModelTypeName"));
- }
-
- [Fact]
- public void ModelInfo_HasModelNamespaceProperty_Net9()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("ModelNamespace"));
- }
-
- [Fact]
- public void ModelInfo_HasModelFullNameProperty_Net9()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("ModelFullName"));
- }
-
- [Fact]
- public void ModelInfo_HasModelTypeNameCapitalizedProperty_Net9()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("ModelTypeNameCapitalized"));
- }
-
- [Fact]
- public void ModelInfo_HasModelTypePluralNameProperty_Net9()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("ModelTypePluralName"));
- }
-
- [Fact]
- public void ModelInfo_HasModelVariableProperty_Net9()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("ModelVariable"));
- }
-
- [Fact]
- public void ModelInfo_HasPrimaryKeyNameProperty_Net9()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("PrimaryKeyName"));
- }
-
- [Fact]
- public void ModelInfo_HasPrimaryKeyShortTypeNameProperty_Net9()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("PrimaryKeyShortTypeName"));
- }
-
- [Fact]
- public void ModelInfo_HasPrimaryKeyTypeNameProperty_Net9()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("PrimaryKeyTypeName"));
- }
-
- [Fact]
- public void ModelInfo_ComputedProperties_WorkCorrectly_Net9()
- {
- var modelInfo = new ModelInfo { ModelTypeName = "product" };
- Assert.Equal("Product", modelInfo.ModelTypeNameCapitalized);
- Assert.Equal("products", modelInfo.ModelTypePluralName);
- Assert.Equal("product", modelInfo.ModelVariable);
- }
-
- #endregion
-
- #region PackageConstants — EF
-
- [Fact]
- public void PackageConstants_SqlServer_HasCorrectKey_Net9()
- {
- Assert.Equal("sqlserver-efcore", PackageConstants.EfConstants.SqlServer);
- }
-
- [Fact]
- public void PackageConstants_SQLite_HasCorrectKey_Net9()
- {
- Assert.Equal("sqlite-efcore", PackageConstants.EfConstants.SQLite);
- }
-
- [Fact]
- public void PackageConstants_CosmosDb_HasCorrectKey_Net9()
- {
- Assert.Equal("cosmos-efcore", PackageConstants.EfConstants.CosmosDb);
- }
-
- [Fact]
- public void PackageConstants_Postgres_HasCorrectKey_Net9()
- {
- Assert.Equal("npgsql-efcore", PackageConstants.EfConstants.Postgres);
- }
-
- [Fact]
- public void PackageConstants_EfCorePackage_HasCorrectName_Net9()
- {
- Assert.Equal("Microsoft.EntityFrameworkCore", PackageConstants.EfConstants.EfCorePackage.Name);
- }
-
- [Fact]
- public void PackageConstants_EfCorePackage_RequiresVersion_Net9()
- {
- Assert.True(PackageConstants.EfConstants.EfCorePackage.IsVersionRequired);
- }
-
- [Fact]
- public void PackageConstants_EfCoreToolsPackage_HasCorrectName_Net9()
- {
- Assert.Equal("Microsoft.EntityFrameworkCore.Tools", PackageConstants.EfConstants.EfCoreToolsPackage.Name);
- }
-
- [Fact]
- public void PackageConstants_EfCoreToolsPackage_RequiresVersion_Net9()
- {
- Assert.True(PackageConstants.EfConstants.EfCoreToolsPackage.IsVersionRequired);
- }
-
- [Fact]
- public void PackageConstants_SqlServerPackage_HasCorrectName_Net9()
- {
- Assert.Equal("Microsoft.EntityFrameworkCore.SqlServer", PackageConstants.EfConstants.SqlServerPackage.Name);
- }
-
- [Fact]
- public void PackageConstants_SqlitePackage_HasCorrectName_Net9()
- {
- Assert.Equal("Microsoft.EntityFrameworkCore.Sqlite", PackageConstants.EfConstants.SqlitePackage.Name);
- }
-
- [Fact]
- public void PackageConstants_CosmosPackage_HasCorrectName_Net9()
- {
- Assert.Equal("Microsoft.EntityFrameworkCore.Cosmos", PackageConstants.EfConstants.CosmosPackage.Name);
- }
-
- [Fact]
- public void PackageConstants_PostgresPackage_HasCorrectName_Net9()
- {
- Assert.Equal("Npgsql.EntityFrameworkCore.PostgreSQL", PackageConstants.EfConstants.PostgresPackage.Name);
- }
-
- [Fact]
- public void PackageConstants_EfPackagesDict_Contains4Providers_Net9()
- {
- Assert.Equal(4, PackageConstants.EfConstants.EfPackagesDict.Count);
- }
-
- [Fact]
- public void PackageConstants_EfPackagesDict_ContainsSqlServer_Net9()
- {
- Assert.True(PackageConstants.EfConstants.EfPackagesDict.ContainsKey(PackageConstants.EfConstants.SqlServer));
- }
-
- [Fact]
- public void PackageConstants_EfPackagesDict_ContainsSQLite_Net9()
- {
- Assert.True(PackageConstants.EfConstants.EfPackagesDict.ContainsKey(PackageConstants.EfConstants.SQLite));
- }
-
- [Fact]
- public void PackageConstants_EfPackagesDict_ContainsCosmosDb_Net9()
- {
- Assert.True(PackageConstants.EfConstants.EfPackagesDict.ContainsKey(PackageConstants.EfConstants.CosmosDb));
- }
-
- [Fact]
- public void PackageConstants_EfPackagesDict_ContainsPostgres_Net9()
- {
- Assert.True(PackageConstants.EfConstants.EfPackagesDict.ContainsKey(PackageConstants.EfConstants.Postgres));
- }
-
- [Fact]
- public void PackageConstants_ConnectionStringVariableName_IsCorrect_Net9()
- {
- Assert.Equal("connectionString", PackageConstants.EfConstants.ConnectionStringVariableName);
- }
-
- #endregion
-
- #region UseDatabaseMethods
-
- [Fact]
- public void UseDatabaseMethods_SqlServer_UseSqlServer_Net9()
- {
- Assert.True(PackageConstants.EfConstants.UseDatabaseMethods.ContainsKey(PackageConstants.EfConstants.SqlServer));
- Assert.Equal("UseSqlServer", PackageConstants.EfConstants.UseDatabaseMethods[PackageConstants.EfConstants.SqlServer]);
- }
-
- [Fact]
- public void UseDatabaseMethods_SQLite_UseSqlite_Net9()
- {
- Assert.True(PackageConstants.EfConstants.UseDatabaseMethods.ContainsKey(PackageConstants.EfConstants.SQLite));
- Assert.Equal("UseSqlite", PackageConstants.EfConstants.UseDatabaseMethods[PackageConstants.EfConstants.SQLite]);
- }
-
- [Fact]
- public void UseDatabaseMethods_Postgres_UseNpgsql_Net9()
- {
- Assert.True(PackageConstants.EfConstants.UseDatabaseMethods.ContainsKey(PackageConstants.EfConstants.Postgres));
- Assert.Equal("UseNpgsql", PackageConstants.EfConstants.UseDatabaseMethods[PackageConstants.EfConstants.Postgres]);
- }
-
- [Fact]
- public void UseDatabaseMethods_CosmosDb_UseCosmos_Net9()
- {
- Assert.True(PackageConstants.EfConstants.UseDatabaseMethods.ContainsKey(PackageConstants.EfConstants.CosmosDb));
- Assert.Equal("UseCosmos", PackageConstants.EfConstants.UseDatabaseMethods[PackageConstants.EfConstants.CosmosDb]);
- }
-
- #endregion
-
- #region Template Folder Verification — Net9 (.tt text template format)
-
- [Fact]
- public void Net9TemplateFolder_ContainsApiEfControllerTtTemplate_Net9()
- {
- // Net9 uses .tt text templates, not legacy .cshtml
- var assembly = typeof(EfControllerHelper).Assembly;
- string basePath = Path.GetDirectoryName(assembly.Location)!;
- string templatePath = Path.Combine(basePath, "Templates", TargetFramework, "EfController", "ApiEfController.tt");
-
- if (File.Exists(templatePath))
- {
- string content = File.ReadAllText(templatePath);
- Assert.NotEmpty(content);
- }
- else
- {
- // .tt templates may be compiled into the assembly rather than deployed as files
- Assert.True(true, ".tt template expected compiled into assembly at build time");
- }
- }
-
- [Fact]
- public void Net9TemplateFolder_ContainsMvcEfControllerTtTemplate_Net9()
- {
- var assembly = typeof(EfControllerHelper).Assembly;
- string basePath = Path.GetDirectoryName(assembly.Location)!;
- string templatePath = Path.Combine(basePath, "Templates", TargetFramework, "EfController", "MvcEfController.tt");
-
- if (File.Exists(templatePath))
- {
- string content = File.ReadAllText(templatePath);
- Assert.NotEmpty(content);
- }
- else
- {
- Assert.True(true, ".tt template expected compiled into assembly at build time");
- }
- }
-
- [Fact]
- public void Net9TemplateFolder_DoesNotUseLegacyCshtmlTemplates_Net9()
- {
- // Net9 EfController folder should NOT have .cshtml templates (those are only in net8.0)
- var assembly = typeof(EfControllerHelper).Assembly;
- string basePath = Path.GetDirectoryName(assembly.Location)!;
- string efControllerDir = Path.Combine(basePath, "Templates", TargetFramework, "EfController");
-
- if (Directory.Exists(efControllerDir))
- {
- var cshtmlFiles = Directory.GetFiles(efControllerDir, "*.cshtml");
- Assert.Empty(cshtmlFiles);
- }
- else
- {
- // Templates compiled into assembly; no physical folder expected
- Assert.True(true);
- }
- }
-
- #endregion
-
- #region Net9 Template Type Resolution — Uses net10 compiled types
-
- [Fact]
- public void Net9TemplateTypes_Net9CsFilesExcludedFromCompilation_Net9()
- {
- // Net9 .tt templates are source files only; their .cs files are excluded from compilation
- // via in the csproj.
- // Both Net9 and Net10 TFMs use the compiled Templates.net10.EfController types.
- var assembly = typeof(EfControllerHelper).Assembly;
- var allTypes = assembly.GetTypes();
- var net10EfControllerTypes = allTypes.Where(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.EfController")).ToList();
-
- Assert.True(net10EfControllerTypes.Count > 0, "Expected net10 EfController template types used for all TFMs");
- }
-
- [Fact]
- public void Net9TemplateTypes_UsesNet10ApiEfController_Net9()
- {
- // Net9 resolves to the same ApiEfController type in Templates.net10.EfController
- var assembly = typeof(EfControllerHelper).Assembly;
- var allTypes = assembly.GetTypes();
- var apiType = allTypes.FirstOrDefault(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.EfController") &&
- t.Name.Equals("ApiEfController", StringComparison.OrdinalIgnoreCase));
-
- Assert.NotNull(apiType);
- }
-
- [Fact]
- public void Net9TemplateTypes_UsesNet10MvcEfController_Net9()
- {
- // Net9 resolves to the same MvcEfController type in Templates.net10.EfController
- var assembly = typeof(EfControllerHelper).Assembly;
- var allTypes = assembly.GetTypes();
- var mvcType = allTypes.FirstOrDefault(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.EfController") &&
- t.Name.Equals("MvcEfController", StringComparison.OrdinalIgnoreCase));
-
- Assert.NotNull(mvcType);
- }
-
- #endregion
-
- #region EfControllerHelper — GetCrudControllerType maps to net10 types
-
- [Fact]
- public void EfControllerHelper_TemplateTypes_AreResolvableFromAssembly_Net9()
- {
- // EfControllerHelper.GetCrudControllerType maps to Templates.net10.EfController types
- var assembly = typeof(EfControllerHelper).Assembly;
- var allTypes = assembly.GetTypes();
- var net10EfControllerTypes = allTypes.Where(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.EfController")).ToList();
-
- Assert.True(net10EfControllerTypes.Count > 0, "Expected net10 EfController template types in assembly");
- }
-
- [Fact]
- public void EfControllerHelper_ApiEfController_Net10TemplateTypeExists_Net9()
- {
- var assembly = typeof(EfControllerHelper).Assembly;
- var allTypes = assembly.GetTypes();
- var apiType = allTypes.FirstOrDefault(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.EfController") &&
- t.Name.Equals("ApiEfController", StringComparison.OrdinalIgnoreCase));
-
- Assert.NotNull(apiType);
- }
-
- [Fact]
- public void EfControllerHelper_MvcEfController_Net10TemplateTypeExists_Net9()
- {
- var assembly = typeof(EfControllerHelper).Assembly;
- var allTypes = assembly.GetTypes();
- var mvcType = allTypes.FirstOrDefault(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.EfController") &&
- t.Name.Equals("MvcEfController", StringComparison.OrdinalIgnoreCase));
-
- Assert.NotNull(mvcType);
- }
-
- [Fact]
- public void EfControllerHelper_ThrowsWhenProjectInfoNull_Net9()
- {
- var model = new EfControllerModel
- {
- ControllerType = "API",
- ControllerName = "ProductsController",
- ControllerOutputPath = "Controllers",
- DbContextInfo = new DbContextInfo { DbContextClassName = "AppDbContext", EfScenario = true },
- ModelInfo = new ModelInfo { ModelTypeName = "Product" },
- ProjectInfo = new ProjectInfo(null)
- };
-
- Assert.Throws(() =>
- EfControllerHelper.GetEfControllerTemplatingProperty(model));
- }
-
- #endregion
-
- #region Code Modification Configs
-
- [Fact]
- public void Net9CodeModificationConfig_EfControllerChanges_Exists_Net9()
- {
- // The code currently hardcodes net11.0 for the targetFrameworkFolder
- var assembly = typeof(EfControllerHelper).Assembly;
- string basePath = Path.GetDirectoryName(assembly.Location)!;
- string configPath = Path.Combine(basePath, "Templates", "net11.0", "CodeModificationConfigs", "efControllerChanges.json");
-
- if (File.Exists(configPath))
- {
- string content = File.ReadAllText(configPath);
- Assert.Contains("Program.cs", content);
- }
- else
- {
- Assert.True(true, "Config file expected embedded in assembly");
- }
- }
-
- #endregion
-
- #region Pipeline Step Sequence
-
- [Fact]
- public void ApiControllerCrudPipeline_DefinesCorrectStepSequence_Net9()
- {
- // API Controller CRUD pipeline: ValidateEfControllerStep → WithEfControllerAddPackagesStep → WithDbContextStep
- // → WithAspNetConnectionStringStep → WithEfControllerTextTemplatingStep → WithEfControllerCodeChangeStep
- Assert.NotNull(typeof(ValidateEfControllerStep));
- Assert.True(typeof(ValidateEfControllerStep).IsClass);
+ protected override string TargetFramework => "net9.0";
+ protected override string TestClassName => nameof(ApiControllerNet9IntegrationTests);
+
+ [Fact]
+ public async Task Scaffold_ApiControllerCrud_Net9_CliInvocation()
+ {
+ // Arrange — set up project with Program.cs and a model class
+ File.WriteAllText(_testProjectPath, ProjectContent);
+ File.WriteAllText(Path.Combine(_testProjectDir, "Program.cs"), ScaffoldCliHelper.GetMinimalProgramCs());
+ var modelsDir = Path.Combine(_testProjectDir, "Models");
+ Directory.CreateDirectory(modelsDir);
+ File.WriteAllText(Path.Combine(modelsDir, "TestModel.cs"), ScaffoldCliHelper.GetModelClassContent("TestProject", "TestModel"));
+
+ // Verify project builds before scaffolding
+ var (beforeExitCode, _, beforeError) = await RunBuildAsync(_testProjectDir);
+ Assert.True(beforeExitCode == 0, $"Project should build before scaffolding. Error: {beforeError}");
+
+ // Act — invoke CLI: dotnet scaffold aspnet apicontroller-crud
+ var (cliExitCode, cliOutput, cliError) = await ScaffoldCliHelper.RunScaffoldAsync(
+ TargetFramework,
+ "apicontroller-crud",
+ "--project", _testProjectPath,
+ "--model", "TestModel",
+ "--controller", "TestApiController",
+ "--dataContext", "TestDbContext",
+ "--dbProvider", "sqlite-efcore");
+ Assert.True(cliExitCode == 0, $"CLI scaffold should succeed.\nOutput: {cliOutput}\nError: {cliError}");
+
+ // Assert — expected files were created
+ Assert.True(File.Exists(Path.Combine(_testProjectDir, "Controllers", "TestApiController.cs")),
+ "Controller file 'Controllers/TestApiController.cs' should be created.");
+ Assert.True(File.Exists(Path.Combine(_testProjectDir, "Data", "TestDbContext.cs")),
+ "DbContext file 'Data/TestDbContext.cs' should be created.");
+ var programContent = File.ReadAllText(Path.Combine(_testProjectDir, "Program.cs"));
+ Assert.Contains("TestDbContext", programContent);
+
+ // Assert — no NuGet errors and project builds after scaffolding
+ Assert.False(cliOutput.Contains("error: NU"),
+ $"Scaffolding should not produce NuGet errors for {TargetFramework}.\nOutput: {cliOutput}");
+ var (afterExitCode, _, afterError) = await RunBuildAsync(_testProjectDir);
+ Assert.True(afterExitCode == 0, $"Project should still build after scaffolding. Error: {afterError}");
}
-
- [Fact]
- public void MvcControllerCrudPipeline_HasAdditionalMvcViewsStep_Net9()
- {
- // MVC Controller CRUD pipeline adds WithMvcViewsStep() on top of API pipeline
- var extensionType = typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions);
- var method = extensionType.GetMethod("WithMvcViewsStep", BindingFlags.Public | BindingFlags.Static);
- Assert.NotNull(method);
- }
-
- [Fact]
- public void EfControllerPipeline_AllKeyStepsInheritFromScaffoldStep_Net9()
- {
- Assert.True(typeof(ValidateEfControllerStep).IsAssignableTo(typeof(ScaffoldStep)));
- }
-
- [Fact]
- public void EfControllerPipeline_AllKeyStepsAreInScaffoldStepsNamespace_Net9()
- {
- string expectedNs = "Microsoft.DotNet.Tools.Scaffold.AspNet.ScaffoldSteps";
- Assert.Equal(expectedNs, typeof(ValidateEfControllerStep).Namespace);
- }
-
- #endregion
-
- #region Builder Extensions
-
- [Fact]
- public void EfControllerBuilderExtensions_WithEfControllerTextTemplatingStep_Exists_Net9()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions);
- var method = extensionType.GetMethod("WithEfControllerTextTemplatingStep", BindingFlags.Public | BindingFlags.Static);
- Assert.NotNull(method);
- }
-
- [Fact]
- public void EfControllerBuilderExtensions_WithEfControllerAddPackagesStep_Exists_Net9()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions);
- var method = extensionType.GetMethod("WithEfControllerAddPackagesStep", BindingFlags.Public | BindingFlags.Static);
- Assert.NotNull(method);
- }
-
- [Fact]
- public void EfControllerBuilderExtensions_WithEfControllerCodeChangeStep_Exists_Net9()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions);
- var method = extensionType.GetMethod("WithEfControllerCodeChangeStep", BindingFlags.Public | BindingFlags.Static);
- Assert.NotNull(method);
- }
-
- [Fact]
- public void EfControllerBuilderExtensions_WithMvcViewsStep_Exists_Net9()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions);
- var method = extensionType.GetMethod("WithMvcViewsStep", BindingFlags.Public | BindingFlags.Static);
- Assert.NotNull(method);
- }
-
- [Fact]
- public void EfControllerBuilderExtensions_Has4ExtensionMethods_Net9()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions);
- var methods = extensionType.GetMethods(BindingFlags.Public | BindingFlags.Static)
- .Where(m => m.GetParameters().Any(p => p.ParameterType == typeof(IScaffoldBuilder)))
- .ToList();
- Assert.Equal(4, methods.Count);
- }
-
- [Fact]
- public void EfControllerBuilderExtensions_AllMethodsReturnIScaffoldBuilder_Net9()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions);
- var methods = extensionType.GetMethods(BindingFlags.Public | BindingFlags.Static)
- .Where(m => m.GetParameters().Any(p => p.ParameterType == typeof(IScaffoldBuilder)))
- .ToList();
-
- foreach (var method in methods)
- {
- Assert.Equal(typeof(IScaffoldBuilder), method.ReturnType);
- }
- }
-
- #endregion
-
- #region TFM Availability
-
- [Fact]
- public void ApiControllerCrud_IsAvailableForNet9_Net9()
- {
- // API category is available for all TFMs including Net9
- Assert.Equal("API", AspnetStrings.Catagories.API);
- }
-
- [Fact]
- public void MvcControllerCrud_IsAvailableForNet9_Net9()
- {
- // MVC category is available for all TFMs including Net9
- Assert.Equal("MVC", AspnetStrings.Catagories.MVC);
- }
-
- [Fact]
- public void CommandInfoExtensions_IsCommandAnAspNetCommand_Exists_Net9()
- {
- var method = typeof(CommandInfoExtensions).GetMethod("IsCommandAnAspNetCommand");
- Assert.NotNull(method);
- }
-
- #endregion
-
- #region Cancellation Support
-
- [Fact]
- public async Task ValidateEfControllerStep_AcceptsCancellationToken_Net9()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext"
- };
-
- using var cts = new CancellationTokenSource();
- bool result = await step.ExecuteAsync(_context, cts.Token);
-
- Assert.False(result);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_ExecuteAsync_IsInherited_Net9()
- {
- var method = typeof(ValidateEfControllerStep).GetMethod("ExecuteAsync", new[] { typeof(ScaffolderContext), typeof(CancellationToken) });
- Assert.NotNull(method);
- Assert.True(method!.IsVirtual);
- }
-
- #endregion
-
- #region Scaffolder Registration Constants
-
- [Fact]
- public void ApiControllerCrud_UsesCorrectName_Net9()
- {
- Assert.Equal("apicontroller-crud", AspnetStrings.Api.ApiControllerCrud);
- }
-
- [Fact]
- public void ApiControllerCrud_UsesCorrectDisplayName_Net9()
- {
- Assert.Equal("API Controller with actions, using Entity Framework (CRUD)", AspnetStrings.Api.ApiControllerCrudDisplayName);
- }
-
- [Fact]
- public void ApiControllerCrud_UsesCorrectCategory_Net9()
- {
- Assert.Equal("API", AspnetStrings.Catagories.API);
- }
-
- [Fact]
- public void ApiControllerCrud_UsesCorrectDescription_Net9()
- {
- Assert.Equal("Create an API controller with REST actions to create, read, update, delete, and list entities", AspnetStrings.Api.ApiControllerCrudDescription);
- }
-
- [Fact]
- public void ApiControllerCrud_Has2Examples_Net9()
- {
- Assert.NotEmpty(AspnetStrings.Api.ApiControllerCrudExample1);
- Assert.NotEmpty(AspnetStrings.Api.ApiControllerCrudExample2);
- Assert.NotEmpty(AspnetStrings.Api.ApiControllerCrudExample1Description);
- Assert.NotEmpty(AspnetStrings.Api.ApiControllerCrudExample2Description);
- }
-
- [Fact]
- public void MvcControllerCrud_Has2Examples_Net9()
- {
- Assert.NotEmpty(AspnetStrings.MVC.ControllerCrudExample1);
- Assert.NotEmpty(AspnetStrings.MVC.ControllerCrudExample2);
- Assert.NotEmpty(AspnetStrings.MVC.ControllerCrudExample1Description);
- Assert.NotEmpty(AspnetStrings.MVC.ControllerCrudExample2Description);
- }
-
- #endregion
-
- #region Scaffolding Context Properties
-
- [Fact]
- public void ScaffolderContext_CanStoreEfControllerModel_Net9()
- {
- var model = new EfControllerModel
- {
- ControllerType = "API",
- ControllerName = "ProductsController",
- ControllerOutputPath = Path.Combine(_testProjectDir, "Controllers"),
- DbContextInfo = new DbContextInfo { DbContextClassName = "AppDbContext", EfScenario = true },
- ModelInfo = new ModelInfo { ModelTypeName = "Product" },
- ProjectInfo = new ProjectInfo(_testProjectPath)
- };
-
- _context.Properties.Add(nameof(EfControllerModel), model);
-
- Assert.True(_context.Properties.ContainsKey(nameof(EfControllerModel)));
- var retrieved = _context.Properties[nameof(EfControllerModel)] as EfControllerModel;
- Assert.NotNull(retrieved);
- Assert.Equal("API", retrieved!.ControllerType);
- Assert.Equal("ProductsController", retrieved.ControllerName);
- Assert.Equal("Product", retrieved.ModelInfo.ModelTypeName);
- Assert.True(retrieved.DbContextInfo.EfScenario);
- }
-
- [Fact]
- public void ScaffolderContext_CanStoreEfControllerSettings_Net9()
- {
- var settings = new EfControllerSettings
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer,
- Prerelease = false
- };
-
- _context.Properties.Add(nameof(EfControllerSettings), settings);
-
- Assert.True(_context.Properties.ContainsKey(nameof(EfControllerSettings)));
- var retrieved = _context.Properties[nameof(EfControllerSettings)] as EfControllerSettings;
- Assert.NotNull(retrieved);
- Assert.Equal(_testProjectPath, retrieved!.Project);
- Assert.Equal("API", retrieved.ControllerType);
- Assert.Equal("Product", retrieved.Model);
- }
-
- [Fact]
- public void ScaffolderContext_CanStoreCodeModifierProperties_Net9()
- {
- var codeModifierProperties = new Dictionary
- {
- { "DbContextName", "AppDbContext" },
- { "ConnectionStringName", "DefaultConnection" }
- };
-
- _context.Properties.Add(Scaffolding.Internal.Constants.StepConstants.CodeModifierProperties, codeModifierProperties);
-
- Assert.True(_context.Properties.ContainsKey(Scaffolding.Internal.Constants.StepConstants.CodeModifierProperties));
- var retrieved = _context.Properties[Scaffolding.Internal.Constants.StepConstants.CodeModifierProperties] as Dictionary;
- Assert.NotNull(retrieved);
- Assert.Equal(2, retrieved!.Count);
- }
-
- #endregion
-
- #region ControllerOutputPath Constant
-
- [Fact]
- public void ControllerCommandOutput_IsControllers_Net9()
- {
- Assert.Equal("Controllers", AspNetConstants.DotnetCommands.ControllerCommandOutput);
- }
-
- #endregion
-
- #region NewDbContext Constant
-
- [Fact]
- public void NewDbContext_HasCorrectValue_Net9()
- {
- Assert.Equal("NewDbContext", AspNetConstants.NewDbContext);
- }
-
- #endregion
-
- #region File Extensions
-
- [Fact]
- public void CSharpExtension_IsCorrect_Net9()
- {
- Assert.Equal(".cs", AspNetConstants.CSharpExtension);
- }
-
- #endregion
-
- #region Validation Combination Tests
-
- [Fact]
- public async Task ValidateEfControllerStep_NullProject_FailsValidation_Net9()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = null,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext"
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_NullModel_FailsValidation_Net9()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = null,
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = "AppDbContext"
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_NullControllerName_FailsValidation_Net9()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = null,
- ControllerType = "API",
- DataContext = "AppDbContext"
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_NullControllerType_FailsValidation_Net9()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = null,
- DataContext = "AppDbContext"
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_NullDataContext_FailsValidation_Net9()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- ControllerName = "ProductsController",
- ControllerType = "API",
- DataContext = null
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- [Fact]
- public async Task ValidateEfControllerStep_AllFieldsEmpty_FailsValidation_Net9()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateEfControllerStep(_mockFileSystem.Object, new Mock>().Object, _testTelemetryService)
- {
- Project = string.Empty,
- Model = string.Empty,
- ControllerName = string.Empty,
- ControllerType = string.Empty,
- DataContext = string.Empty
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- #endregion
-
- #region Regression Guards
-
- [Fact]
- public void EfControllerModel_IsInModelsNamespace_Net9()
- {
- Assert.Equal("Microsoft.DotNet.Tools.Scaffold.AspNet.Models", typeof(EfControllerModel).Namespace);
- }
-
- [Fact]
- public void EfControllerSettings_IsInSettingsNamespace_Net9()
- {
- Assert.Equal("Microsoft.DotNet.Tools.Scaffold.AspNet.ScaffoldSteps.Settings", typeof(EfControllerSettings).Namespace);
- }
-
- [Fact]
- public void EfControllerHelper_IsInHelpersNamespace_Net9()
- {
- Assert.Equal("Microsoft.DotNet.Tools.Scaffold.AspNet.Helpers", typeof(EfControllerHelper).Namespace);
- }
-
- [Fact]
- public void ValidateEfControllerStep_IsInternal_Net9()
- {
- Assert.False(typeof(ValidateEfControllerStep).IsPublic);
- }
-
- [Fact]
- public void EfControllerModel_IsInternal_Net9()
- {
- Assert.False(typeof(EfControllerModel).IsPublic);
- }
-
- [Fact]
- public void EfControllerSettings_IsInternal_Net9()
- {
- Assert.False(typeof(EfControllerSettings).IsPublic);
- }
-
- [Fact]
- public void EfControllerScaffolderBuilderExtensions_IsInternal_Net9()
- {
- Assert.False(typeof(Scaffolding.Core.Hosting.EfControllerScaffolderBuilderExtensions).IsPublic);
- }
-
- [Fact]
- public void EfControllerHelper_IsInternal_Net9()
- {
- Assert.False(typeof(EfControllerHelper).IsPublic);
- }
-
- [Fact]
- public void EfControllerHelper_IsStatic_Net9()
- {
- Assert.True(typeof(EfControllerHelper).IsAbstract && typeof(EfControllerHelper).IsSealed);
- }
-
- [Fact]
- public void DbContextInfo_IsInternal_Net9()
- {
- Assert.False(typeof(DbContextInfo).IsPublic);
- }
-
- [Fact]
- public void ModelInfo_IsInternal_Net9()
- {
- Assert.False(typeof(ModelInfo).IsPublic);
- }
-
- #endregion
-
- #region API Controller Scaffolder — Non-CRUD Strings
-
- [Fact]
- public void ApiControllerNonCrud_Name_IsApiController_Net9()
- {
- Assert.Equal("apicontroller", AspnetStrings.Api.ApiController);
- }
-
- [Fact]
- public void ApiControllerNonCrud_DisplayName_Net9()
- {
- Assert.Equal("API Controller", AspnetStrings.Api.ApiControllerDisplayName);
- }
-
- [Fact]
- public void MvcControllerNonCrud_Name_IsMvcController_Net9()
- {
- Assert.Equal("mvccontroller", AspnetStrings.MVC.Controller);
- }
-
- [Fact]
- public void MvcControllerNonCrud_DisplayName_Net9()
- {
- Assert.Equal("MVC Controller", AspnetStrings.MVC.DisplayName);
- }
-
- #endregion
-
- #region ControllerType Values
-
- [Fact]
- public void ControllerType_APIValue_MatchesCategoryName_Net9()
- {
- Assert.Equal("API", AspnetStrings.Catagories.API);
- }
-
- [Fact]
- public void ControllerType_MVCValue_MatchesCategoryName_Net9()
- {
- Assert.Equal("MVC", AspnetStrings.Catagories.MVC);
- }
-
- #endregion
-
- #region TestTelemetryService Helper
-
- private class TestTelemetryService : ITelemetryService
- {
- public List<(string EventName, IReadOnlyDictionary Properties, IReadOnlyDictionary Measurements)> TrackedEvents { get; } = new();
-
- public void TrackEvent(string eventName, IReadOnlyDictionary properties, IReadOnlyDictionary measurements)
- {
- TrackedEvents.Add((eventName, properties, measurements));
- }
-
- public void Flush()
- {
- }
- }
-
- #endregion
}
diff --git a/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/MinimalApiIntegrationTestsBase.cs b/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/MinimalApiIntegrationTestsBase.cs
new file mode 100644
index 000000000..e8666e0f2
--- /dev/null
+++ b/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/MinimalApiIntegrationTestsBase.cs
@@ -0,0 +1,318 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using Microsoft.DotNet.Tools.Scaffold.Tests.Helpers;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+using Microsoft.DotNet.Scaffolding.Core.Scaffolders;
+using Microsoft.DotNet.Scaffolding.Internal.Services;
+using Microsoft.DotNet.Tools.Scaffold.AspNet;
+using Microsoft.DotNet.Tools.Scaffold.AspNet.Commands;
+using Microsoft.DotNet.Tools.Scaffold.AspNet.Common;
+using Microsoft.DotNet.Tools.Scaffold.AspNet.ScaffoldSteps;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using Moq;
+using Xunit;
+
+namespace Microsoft.DotNet.Tools.Scaffold.Tests.AspNet.Integration;
+
+///
+/// Shared base class for Minimal API integration tests across .NET versions.
+///
+public abstract class MinimalApiIntegrationTestsBase : IDisposable
+{
+ protected abstract string TargetFramework { get; }
+ protected abstract string TestClassName { get; }
+
+ protected readonly string _testDirectory;
+ protected readonly string _testProjectDir;
+ protected readonly string _testProjectPath;
+ protected readonly Mock _mockFileSystem;
+ protected readonly TestTelemetryService _testTelemetryService;
+ protected readonly Mock _mockScaffolder;
+ protected readonly ScaffolderContext _context;
+
+ protected MinimalApiIntegrationTestsBase()
+ {
+ _testDirectory = Path.Combine(Path.GetTempPath(), TestClassName, Guid.NewGuid().ToString());
+ _testProjectDir = Path.Combine(_testDirectory, "TestProject");
+ _testProjectPath = Path.Combine(_testProjectDir, "TestProject.csproj");
+ Directory.CreateDirectory(_testProjectDir);
+
+ _mockFileSystem = new Mock();
+ _testTelemetryService = new TestTelemetryService();
+
+ _mockScaffolder = new Mock();
+ _mockScaffolder.Setup(s => s.DisplayName).Returns(AspnetStrings.Api.MinimalApiDisplayName);
+ _mockScaffolder.Setup(s => s.Name).Returns(AspnetStrings.Api.MinimalApi);
+ _context = new ScaffolderContext(_mockScaffolder.Object);
+ }
+
+ public void Dispose()
+ {
+ if (Directory.Exists(_testDirectory))
+ {
+ try { Directory.Delete(_testDirectory, recursive: true); }
+ catch { /* best-effort cleanup */ }
+ }
+ }
+
+ protected string ProjectContent => $@"
+
+ {TargetFramework}
+ enable
+
+";
+
+ #region ValidateMinimalApiStep — Validation Logic
+
+ [Fact]
+ public async Task ValidateMinimalApiStep_FailsWithNullProject()
+ {
+ var step = CreateValidateMinimalApiStep();
+ step.Project = null;
+ step.Model = "Product";
+ step.Endpoints = "ProductEndpoints";
+ step.DataContext = "AppDbContext";
+ step.DatabaseProvider = PackageConstants.EfConstants.SQLite;
+
+ var result = await step.ExecuteAsync(_context);
+ Assert.False(result);
+ }
+
+ [Fact]
+ public async Task ValidateMinimalApiStep_FailsWithEmptyProject()
+ {
+ var step = CreateValidateMinimalApiStep();
+ step.Project = string.Empty;
+ step.Model = "Product";
+ step.Endpoints = "ProductEndpoints";
+ step.DataContext = "AppDbContext";
+ step.DatabaseProvider = PackageConstants.EfConstants.SQLite;
+
+ var result = await step.ExecuteAsync(_context);
+ Assert.False(result);
+ }
+
+ [Fact]
+ public async Task ValidateMinimalApiStep_FailsWithNonExistentProject()
+ {
+ _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
+
+ var step = CreateValidateMinimalApiStep();
+ step.Project = @"C:\NonExistent\Project.csproj";
+ step.Model = "Product";
+ step.Endpoints = "ProductEndpoints";
+ step.DataContext = "AppDbContext";
+ step.DatabaseProvider = PackageConstants.EfConstants.SQLite;
+
+ var result = await step.ExecuteAsync(_context);
+ Assert.False(result);
+ }
+
+ [Fact]
+ public async Task ValidateMinimalApiStep_FailsWithNullModel()
+ {
+ _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
+
+ var step = CreateValidateMinimalApiStep();
+ step.Project = _testProjectPath;
+ step.Model = null;
+ step.Endpoints = "ProductEndpoints";
+ step.DataContext = "AppDbContext";
+ step.DatabaseProvider = PackageConstants.EfConstants.SQLite;
+
+ var result = await step.ExecuteAsync(_context);
+ Assert.False(result);
+ }
+
+ [Fact]
+ public async Task ValidateMinimalApiStep_FailsWithEmptyModel()
+ {
+ _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
+
+ var step = CreateValidateMinimalApiStep();
+ step.Project = _testProjectPath;
+ step.Model = string.Empty;
+ step.Endpoints = "ProductEndpoints";
+ step.DataContext = "AppDbContext";
+ step.DatabaseProvider = PackageConstants.EfConstants.SQLite;
+
+ var result = await step.ExecuteAsync(_context);
+ Assert.False(result);
+ }
+
+ [Fact]
+ public async Task ValidateMinimalApiStep_AllFieldsEmpty_FailsValidation()
+ {
+ var step = CreateValidateMinimalApiStep();
+ step.Project = null;
+ step.Model = null;
+ step.Endpoints = null;
+ step.DataContext = null;
+ step.DatabaseProvider = null;
+
+ var result = await step.ExecuteAsync(_context);
+ Assert.False(result);
+ }
+
+ #endregion
+
+ #region Telemetry
+
+ [Fact]
+ public async Task ValidateMinimalApiStep_TracksTelemetry_OnNullProjectFailure()
+ {
+ var step = CreateValidateMinimalApiStep();
+ step.Project = null;
+ step.Model = "Product";
+
+ await step.ExecuteAsync(_context);
+
+ Assert.Single(_testTelemetryService.TrackedEvents);
+ }
+
+ [Fact]
+ public async Task ValidateMinimalApiStep_TracksTelemetry_OnNullModelFailure()
+ {
+ _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
+
+ var step = CreateValidateMinimalApiStep();
+ step.Project = _testProjectPath;
+ step.Model = null;
+
+ await step.ExecuteAsync(_context);
+
+ Assert.Single(_testTelemetryService.TrackedEvents);
+ }
+
+ [Fact]
+ public async Task ValidateMinimalApiStep_SingleEventPerValidation()
+ {
+ var step = CreateValidateMinimalApiStep();
+ step.Project = null;
+
+ await step.ExecuteAsync(_context);
+
+ Assert.Single(_testTelemetryService.TrackedEvents);
+ }
+
+ #endregion
+
+ #region Validation Theories
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ public async Task ValidateMinimalApiStep_FailsWithInvalidModel(string? model)
+ {
+ _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
+
+ var step = CreateValidateMinimalApiStep();
+ step.Project = _testProjectPath;
+ step.Model = model;
+ step.Endpoints = "ProductEndpoints";
+ step.DataContext = "AppDbContext";
+ step.DatabaseProvider = PackageConstants.EfConstants.SQLite;
+
+ var result = await step.ExecuteAsync(_context);
+ Assert.False(result);
+ }
+
+ #endregion
+
+ #region EF Providers — Structure Tests
+
+ [Fact]
+ public void EfPackagesDict_ContainsAllFourProviders()
+ {
+ Assert.Equal(4, PackageConstants.EfConstants.EfPackagesDict.Count);
+ Assert.True(PackageConstants.EfConstants.EfPackagesDict.ContainsKey(PackageConstants.EfConstants.SQLite));
+ Assert.True(PackageConstants.EfConstants.EfPackagesDict.ContainsKey(PackageConstants.EfConstants.SQLite));
+ Assert.True(PackageConstants.EfConstants.EfPackagesDict.ContainsKey(PackageConstants.EfConstants.CosmosDb));
+ Assert.True(PackageConstants.EfConstants.EfPackagesDict.ContainsKey(PackageConstants.EfConstants.Postgres));
+ }
+
+ [Fact]
+ public void UseDatabaseMethods_HasAllFourProviders()
+ {
+ Assert.Equal(4, PackageConstants.EfConstants.UseDatabaseMethods.Count);
+ }
+
+ #endregion
+
+ #region MinimalApi Templates
+
+ [Fact]
+ public void MinimalApiTemplates_FolderExists()
+ {
+ var basePath = GetActualTemplatesBasePath();
+ var minimalApiDir = Path.Combine(basePath, TargetFramework, "MinimalApi");
+ Assert.True(Directory.Exists(minimalApiDir),
+ $"MinimalApi template folder should exist for {TargetFramework}");
+ }
+
+ #endregion
+
+ #region Template Root — Expected Scaffolder Folders
+
+ [Theory]
+ [InlineData("BlazorCrud")]
+ [InlineData("BlazorIdentity")]
+ [InlineData("CodeModificationConfigs")]
+ [InlineData("EfController")]
+ [InlineData("Files")]
+ [InlineData("Identity")]
+ [InlineData("MinimalApi")]
+ [InlineData("RazorPages")]
+ [InlineData("Views")]
+ public void Templates_HasExpectedScaffolderFolder(string folderName)
+ {
+ var basePath = GetActualTemplatesBasePath();
+ var folderPath = Path.Combine(basePath, TargetFramework, folderName);
+ Assert.True(Directory.Exists(folderPath),
+ $"Expected template folder '{folderName}' not found for {TargetFramework}");
+ }
+
+ #endregion
+
+ #region Helper Methods
+
+ private ValidateMinimalApiStep CreateValidateMinimalApiStep()
+ {
+ return new ValidateMinimalApiStep(
+ _mockFileSystem.Object,
+ NullLogger.Instance,
+ _testTelemetryService);
+ }
+
+ protected static string GetActualTemplatesBasePath()
+ {
+ var assemblyLocation = Assembly.GetExecutingAssembly().Location;
+ var assemblyDirectory = Path.GetDirectoryName(assemblyLocation);
+ var basePath = Path.Combine(assemblyDirectory!, "..", "..", "..", "..", "..", "src", "dotnet-scaffolding", "dotnet-scaffold", "AspNet", "Templates");
+ return Path.GetFullPath(basePath);
+ }
+
+ protected Task<(int ExitCode, string Output, string Error)> RunBuildAsync(string workingDirectory)
+ => ScaffoldCliHelper.RunBuildForFrameworkAsync(workingDirectory, TargetFramework);
+
+ protected class TestTelemetryService : ITelemetryService
+ {
+ public List<(string EventName, IReadOnlyDictionary Properties, IReadOnlyDictionary Measures)> TrackedEvents { get; } = new();
+ public void TrackEvent(string eventName, IReadOnlyDictionary? properties = null, IReadOnlyDictionary? measures = null)
+ {
+ TrackedEvents.Add((eventName, properties ?? new Dictionary(), measures ?? new Dictionary()));
+ }
+
+ public void Flush() { }
+ }
+
+ #endregion
+}
diff --git a/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/MinimalApiNet10IntegrationTests.cs b/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/MinimalApiNet10IntegrationTests.cs
index c72bec4ad..fbf5922ec 100644
--- a/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/MinimalApiNet10IntegrationTests.cs
+++ b/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/MinimalApiNet10IntegrationTests.cs
@@ -1,2356 +1,55 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System;
-using System.Collections.Generic;
using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Threading;
using System.Threading.Tasks;
-using Microsoft.DotNet.Scaffolding.Core.Builder;
-using Microsoft.DotNet.Scaffolding.Core.ComponentModel;
-using Microsoft.DotNet.Scaffolding.Core.Scaffolders;
-using Microsoft.DotNet.Scaffolding.Core.Steps;
-using Microsoft.DotNet.Scaffolding.Internal.Services;
-using Microsoft.DotNet.Scaffolding.Internal.Telemetry;
-using Microsoft.DotNet.Scaffolding.TextTemplating;
-using Microsoft.DotNet.Tools.Scaffold.AspNet;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.Commands;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.Common;
-using AspNetConstants = Microsoft.DotNet.Tools.Scaffold.AspNet.Common.Constants;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.Helpers;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.Models;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.ScaffoldSteps;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.ScaffoldSteps.Settings;
-using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Logging.Abstractions;
-using Moq;
+using Microsoft.DotNet.Tools.Scaffold.Tests.Helpers;
using Xunit;
namespace Microsoft.DotNet.Tools.Scaffold.Tests.AspNet.Integration.API;
-///
-/// Integration tests for the Minimal API (minimalapi) scaffolder targeting .NET 10.
-/// Validates scaffolder definition constants, ValidateMinimalApiStep validation logic,
-/// MinimalApiModel/MinimalApiSettings/EfWithModelStepSettings/BaseSettings properties,
-/// MinimalApiHelper template resolution, template folder verification, code modification configs,
-/// package constants, pipeline registration, step dependencies, telemetry tracking,
-/// TFM availability, builder extensions, OpenAPI and TypedResults support,
-/// and database provider support.
-/// .NET 10 MinimalApi templates use the .tt text-templating format (MinimalApi.tt, MinimalApiEf.tt)
-/// with accompanying .cs and .Interfaces.cs generated files. The net10.0 .cs files are excluded
-/// from compilation (), and the compiled
-/// template types are provided by the net11.0 folder under the Templates.net10.MinimalApi namespace.
-///
-public class MinimalApiNet10IntegrationTests : IDisposable
+public class MinimalApiNet10IntegrationTests : MinimalApiIntegrationTestsBase
{
- private const string TargetFramework = "net10.0";
- private readonly string _testDirectory;
- private readonly string _testProjectDir;
- private readonly string _testProjectPath;
- private readonly Mock _mockFileSystem;
- private readonly TestTelemetryService _testTelemetryService;
- private readonly Mock _mockScaffolder;
- private readonly ScaffolderContext _context;
-
- public MinimalApiNet10IntegrationTests()
- {
- _testDirectory = Path.Combine(Path.GetTempPath(), "MinimalApiNet10IntegrationTests", Guid.NewGuid().ToString());
- _testProjectDir = Path.Combine(_testDirectory, "TestProject");
- _testProjectPath = Path.Combine(_testProjectDir, "TestProject.csproj");
- Directory.CreateDirectory(_testProjectDir);
-
- _mockFileSystem = new Mock();
- _testTelemetryService = new TestTelemetryService();
- _mockScaffolder = new Mock();
- _mockScaffolder.Setup(s => s.DisplayName).Returns(AspnetStrings.Api.MinimalApiDisplayName);
- _mockScaffolder.Setup(s => s.Name).Returns(AspnetStrings.Api.MinimalApi);
- _context = new ScaffolderContext(_mockScaffolder.Object);
- }
-
- public void Dispose()
- {
- if (Directory.Exists(_testDirectory))
- {
- try { Directory.Delete(_testDirectory, recursive: true); }
- catch { /* best-effort cleanup */ }
- }
- }
-
- #region Constants & Scaffolder Definition — Minimal API
-
- [Fact]
- public void ScaffolderName_IsMinimalApi_Net10()
- {
- Assert.Equal("minimalapi", AspnetStrings.Api.MinimalApi);
- }
-
- [Fact]
- public void ScaffolderDisplayName_IsMinimalApiDisplayName_Net10()
- {
- Assert.Equal("Minimal API", AspnetStrings.Api.MinimalApiDisplayName);
- }
-
- [Fact]
- public void ScaffolderDescription_IsMinimalApiDescription_Net10()
- {
- Assert.Equal("Generates an endpoints file (with CRUD API endpoints) given a model and optional DbContext.", AspnetStrings.Api.MinimalApiDescription);
- }
-
- [Fact]
- public void ScaffolderCategory_IsAPI_Net10()
- {
- Assert.Equal("API", AspnetStrings.Catagories.API);
- }
-
- [Fact]
- public void ScaffolderExample1_ContainsMinimalApiCommand_Net10()
- {
- Assert.Contains("minimalapi", AspnetStrings.Api.MinimalApiExample1);
- }
-
- [Fact]
- public void ScaffolderExample1_ContainsRequiredOptions_Net10()
- {
- Assert.Contains("--project", AspnetStrings.Api.MinimalApiExample1);
- Assert.Contains("--model", AspnetStrings.Api.MinimalApiExample1);
- Assert.Contains("--endpoints-class", AspnetStrings.Api.MinimalApiExample1);
- Assert.Contains("--data-context", AspnetStrings.Api.MinimalApiExample1);
- Assert.Contains("--database-provider", AspnetStrings.Api.MinimalApiExample1);
- }
-
- [Fact]
- public void ScaffolderExample1_ContainsOpenApiOption_Net10()
- {
- Assert.Contains("--openapi", AspnetStrings.Api.MinimalApiExample1);
- }
-
- [Fact]
- public void ScaffolderExample2_ContainsMinimalApiCommand_Net10()
- {
- Assert.Contains("minimalapi", AspnetStrings.Api.MinimalApiExample2);
- }
-
- [Fact]
- public void ScaffolderExample2_ContainsTypedResultsOption_Net10()
- {
- Assert.Contains("--typed-results", AspnetStrings.Api.MinimalApiExample2);
- }
-
- [Fact]
- public void ScaffolderExample2_ContainsOpenApiOption_Net10()
- {
- Assert.Contains("--openapi", AspnetStrings.Api.MinimalApiExample2);
- }
-
- [Fact]
- public void ScaffolderExample1Description_MentionsOpenAPI_Net10()
- {
- Assert.Contains("OpenAPI", AspnetStrings.Api.MinimalApiExample1Description);
- }
-
- [Fact]
- public void ScaffolderExample2Description_MentionsTypedResults_Net10()
- {
- Assert.Contains("TypedResults", AspnetStrings.Api.MinimalApiExample2Description);
- }
-
- [Fact]
- public void ScaffolderDescription_MentionsEndpointsFile_Net10()
- {
- Assert.Contains("endpoints file", AspnetStrings.Api.MinimalApiDescription);
- }
-
- [Fact]
- public void ScaffolderDescription_MentionsCRUD_Net10()
- {
- Assert.Contains("CRUD", AspnetStrings.Api.MinimalApiDescription);
- }
-
- [Fact]
- public void ScaffolderDescription_MentionsOptionalDbContext_Net10()
- {
- Assert.Contains("optional DbContext", AspnetStrings.Api.MinimalApiDescription);
- }
-
- #endregion
-
- #region CLI Options — Minimal API Specific
-
- [Fact]
- public void CliOption_ProjectOption_IsCorrect_Net10()
- {
- Assert.Equal("--project", AspNetConstants.CliOptions.ProjectCliOption);
- }
-
- [Fact]
- public void CliOption_ModelOption_IsCorrect_Net10()
- {
- Assert.Equal("--model", AspNetConstants.CliOptions.ModelCliOption);
- }
-
- [Fact]
- public void CliOption_DataContextOption_IsCorrect_Net10()
- {
- Assert.Equal("--dataContext", AspNetConstants.CliOptions.DataContextOption);
- }
-
- [Fact]
- public void CliOption_DbProviderOption_IsCorrect_Net10()
- {
- Assert.Equal("--dbProvider", AspNetConstants.CliOptions.DbProviderOption);
- }
-
- [Fact]
- public void CliOption_OpenApiOption_IsCorrect_Net10()
- {
- Assert.Equal("--open", AspNetConstants.CliOptions.OpenApiOption);
- }
-
- [Fact]
- public void CliOption_EndpointsOption_IsCorrect_Net10()
- {
- Assert.Equal("--endpoints", AspNetConstants.CliOptions.EndpointsOption);
- }
-
- [Fact]
- public void CliOption_TypedResultsOption_IsCorrect_Net10()
- {
- Assert.Equal("--typedResults", AspNetConstants.CliOptions.TypedResultsOption);
- }
-
- [Fact]
- public void CliOption_PrereleaseOption_IsCorrect_Net10()
- {
- Assert.Equal("--prerelease", AspNetConstants.CliOptions.PrereleaseCliOption);
- }
-
- #endregion
-
- #region AspNetOptions for MinimalApi
-
- [Fact]
- public void AspNetOptions_HasModelNameProperty_Net10()
- {
- var prop = typeof(AspNetOptions).GetProperty("ModelName");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasEndpointsClassProperty_Net10()
- {
- var prop = typeof(AspNetOptions).GetProperty("EndpointsClass");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasOpenApiProperty_Net10()
- {
- var prop = typeof(AspNetOptions).GetProperty("OpenApi");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasTypedResultsProperty_Net10()
- {
- var prop = typeof(AspNetOptions).GetProperty("TypedResults");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasDataContextClassProperty_Net10()
- {
- var prop = typeof(AspNetOptions).GetProperty("DataContextClass");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasDatabaseProviderProperty_Net10()
- {
- var prop = typeof(AspNetOptions).GetProperty("DatabaseProvider");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasPrereleaseProperty_Net10()
- {
- var prop = typeof(AspNetOptions).GetProperty("Prerelease");
- Assert.NotNull(prop);
- }
-
- #endregion
-
- #region ValidateMinimalApiStep — Properties and Construction
-
- [Fact]
- public void ValidateMinimalApiStep_IsScaffoldStep_Net10()
- {
- Assert.True(typeof(ValidateMinimalApiStep).IsAssignableTo(typeof(ScaffoldStep)));
- }
-
- [Fact]
- public void ValidateMinimalApiStep_HasProjectProperty_Net10()
- {
- Assert.NotNull(typeof(ValidateMinimalApiStep).GetProperty("Project"));
- }
-
- [Fact]
- public void ValidateMinimalApiStep_HasPrereleaseProperty_Net10()
- {
- Assert.NotNull(typeof(ValidateMinimalApiStep).GetProperty("Prerelease"));
- }
-
- [Fact]
- public void ValidateMinimalApiStep_HasEndpointsProperty_Net10()
- {
- Assert.NotNull(typeof(ValidateMinimalApiStep).GetProperty("Endpoints"));
- }
-
- [Fact]
- public void ValidateMinimalApiStep_HasOpenApiProperty_Net10()
- {
- Assert.NotNull(typeof(ValidateMinimalApiStep).GetProperty("OpenApi"));
- }
-
- [Fact]
- public void ValidateMinimalApiStep_HasTypedResultsProperty_Net10()
- {
- Assert.NotNull(typeof(ValidateMinimalApiStep).GetProperty("TypedResults"));
- }
-
- [Fact]
- public void ValidateMinimalApiStep_HasDatabaseProviderProperty_Net10()
- {
- Assert.NotNull(typeof(ValidateMinimalApiStep).GetProperty("DatabaseProvider"));
- }
-
- [Fact]
- public void ValidateMinimalApiStep_HasDataContextProperty_Net10()
- {
- Assert.NotNull(typeof(ValidateMinimalApiStep).GetProperty("DataContext"));
- }
-
- [Fact]
- public void ValidateMinimalApiStep_HasModelProperty_Net10()
- {
- Assert.NotNull(typeof(ValidateMinimalApiStep).GetProperty("Model"));
- }
-
- [Fact]
- public void ValidateMinimalApiStep_CanBeConstructed_Net10()
- {
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService);
-
- Assert.NotNull(step);
- }
-
- [Fact]
- public void ValidateMinimalApiStep_OpenApi_DefaultsToTrue_Net10()
- {
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService);
-
- Assert.True(step.OpenApi);
- }
-
- [Fact]
- public void ValidateMinimalApiStep_TypedResults_DefaultsToTrue_Net10()
- {
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService);
-
- Assert.True(step.TypedResults);
- }
-
- [Fact]
- public void ValidateMinimalApiStep_RequiresIFileSystem_Net10()
- {
- var ctor = typeof(ValidateMinimalApiStep).GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
- Assert.Single(ctor);
- var parameters = ctor[0].GetParameters();
- Assert.Contains(parameters, p => p.ParameterType == typeof(IFileSystem));
- }
-
- [Fact]
- public void ValidateMinimalApiStep_RequiresILogger_Net10()
- {
- var ctor = typeof(ValidateMinimalApiStep).GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
- Assert.Single(ctor);
- var parameters = ctor[0].GetParameters();
- Assert.Contains(parameters, p => p.ParameterType == typeof(ILogger));
- }
-
- [Fact]
- public void ValidateMinimalApiStep_RequiresITelemetryService_Net10()
- {
- var ctor = typeof(ValidateMinimalApiStep).GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
- Assert.Single(ctor);
- var parameters = ctor[0].GetParameters();
- Assert.Contains(parameters, p => p.ParameterType == typeof(ITelemetryService));
- }
-
- #endregion
-
- #region ValidateMinimalApiStep — Validation Logic
-
- [Fact]
- public async Task ValidateMinimalApiStep_FailsWhenProjectMissing_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- Endpoints = "ProductEndpoints",
- OpenApi = true,
- TypedResults = true,
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateMinimalApiStep_FailsWhenProjectFileDoesNotExist_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(false);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- Endpoints = "ProductEndpoints",
- OpenApi = true,
- TypedResults = true,
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateMinimalApiStep_FailsWhenModelMissing_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = string.Empty,
- Endpoints = "ProductEndpoints",
- OpenApi = true,
- TypedResults = true,
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateMinimalApiStep_StepProperties_AreSetCorrectly_Net10()
- {
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- Endpoints = "ProductEndpoints",
- OpenApi = true,
- TypedResults = false,
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer,
- Prerelease = true
- };
-
- Assert.Equal(_testProjectPath, step.Project);
- Assert.Equal("Product", step.Model);
- Assert.Equal("ProductEndpoints", step.Endpoints);
- Assert.True(step.OpenApi);
- Assert.False(step.TypedResults);
- Assert.Equal("AppDbContext", step.DataContext);
- Assert.Equal(PackageConstants.EfConstants.SqlServer, step.DatabaseProvider);
- Assert.True(step.Prerelease);
- }
-
- [Fact]
- public async Task ValidateMinimalApiStep_FailsWhenProjectNull_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = null,
- Model = "Product",
- Endpoints = "ProductEndpoints",
- DataContext = "AppDbContext"
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- [Fact]
- public async Task ValidateMinimalApiStep_FailsWhenModelNull_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = null,
- Endpoints = "ProductEndpoints",
- DataContext = "AppDbContext"
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- [Fact]
- public async Task ValidateMinimalApiStep_AllFieldsEmpty_FailsValidation_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = string.Empty,
- Model = string.Empty,
- Endpoints = string.Empty,
- DataContext = string.Empty
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- #endregion
-
- #region Telemetry
-
- [Fact]
- public async Task TelemetryEventName_IsValidateMinimalApiStepEvent_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- Endpoints = "ProductEndpoints"
- };
-
- await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.Single(_testTelemetryService.TrackedEvents);
- Assert.Equal("ValidateMinimalApiStepEvent", _testTelemetryService.TrackedEvents[0].EventName);
- }
-
- [Fact]
- public async Task TelemetryResult_IsFailure_WhenValidationFails_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- Endpoints = "ProductEndpoints"
- };
-
- await step.ExecuteAsync(_context, CancellationToken.None);
-
- var trackedEvent = _testTelemetryService.TrackedEvents[0];
- Assert.Equal("Failure", trackedEvent.Properties["Result"]);
- }
-
- [Fact]
- public async Task TelemetryScaffolderName_MatchesDisplayName_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- Endpoints = "ProductEndpoints"
- };
-
- await step.ExecuteAsync(_context, CancellationToken.None);
-
- var trackedEvent = _testTelemetryService.TrackedEvents[0];
- Assert.Equal(AspnetStrings.Api.MinimalApiDisplayName, trackedEvent.Properties["ScaffolderName"]);
- }
-
- [Fact]
- public async Task Telemetry_ProjectMissing_TracksFailure_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = null,
- Model = "Product",
- Endpoints = "ProductEndpoints"
- };
-
- await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.Single(_testTelemetryService.TrackedEvents);
- Assert.Equal("Failure", _testTelemetryService.TrackedEvents[0].Properties["Result"]);
- }
-
- [Fact]
- public async Task Telemetry_ModelMissing_TracksFailure_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = string.Empty,
- Endpoints = "ProductEndpoints"
- };
-
- await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.Single(_testTelemetryService.TrackedEvents);
- Assert.Equal("Failure", _testTelemetryService.TrackedEvents[0].Properties["Result"]);
- }
-
- [Fact]
- public async Task Telemetry_EmptyProject_TracksExactlyOneEvent_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- Endpoints = "ProductEndpoints"
- };
-
- await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task Telemetry_FailedValidation_IncludesScaffolderName_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- Endpoints = "ProductEndpoints"
- };
-
- await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.True(_testTelemetryService.TrackedEvents[0].Properties.ContainsKey("ScaffolderName"));
- }
-
- [Fact]
- public async Task Telemetry_FailedValidation_IncludesResult_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- Endpoints = "ProductEndpoints"
- };
-
- await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.True(_testTelemetryService.TrackedEvents[0].Properties.ContainsKey("Result"));
- }
-
- #endregion
-
- #region MinimalApiModel Properties
-
- [Fact]
- public void MinimalApiModel_HasOpenAPIProperty_Net10()
- {
- Assert.NotNull(typeof(MinimalApiModel).GetProperty("OpenAPI"));
- }
-
- [Fact]
- public void MinimalApiModel_HasUseTypedResultsProperty_Net10()
- {
- Assert.NotNull(typeof(MinimalApiModel).GetProperty("UseTypedResults"));
- }
-
- [Fact]
- public void MinimalApiModel_HasEndpointsClassNameProperty_Net10()
- {
- Assert.NotNull(typeof(MinimalApiModel).GetProperty("EndpointsClassName"));
- }
-
- [Fact]
- public void MinimalApiModel_HasEndpointsFileNameProperty_Net10()
- {
- Assert.NotNull(typeof(MinimalApiModel).GetProperty("EndpointsFileName"));
- }
-
- [Fact]
- public void MinimalApiModel_HasEndpointsPathProperty_Net10()
- {
- Assert.NotNull(typeof(MinimalApiModel).GetProperty("EndpointsPath"));
- }
-
- [Fact]
- public void MinimalApiModel_HasEndpointsNamespaceProperty_Net10()
- {
- Assert.NotNull(typeof(MinimalApiModel).GetProperty("EndpointsNamespace"));
- }
-
- [Fact]
- public void MinimalApiModel_HasEndpointsMethodNameProperty_Net10()
- {
- Assert.NotNull(typeof(MinimalApiModel).GetProperty("EndpointsMethodName"));
- }
-
- [Fact]
- public void MinimalApiModel_HasDbContextInfoProperty_Net10()
- {
- Assert.NotNull(typeof(MinimalApiModel).GetProperty("DbContextInfo"));
- }
-
- [Fact]
- public void MinimalApiModel_HasModelInfoProperty_Net10()
- {
- Assert.NotNull(typeof(MinimalApiModel).GetProperty("ModelInfo"));
- }
-
- [Fact]
- public void MinimalApiModel_HasProjectInfoProperty_Net10()
- {
- Assert.NotNull(typeof(MinimalApiModel).GetProperty("ProjectInfo"));
- }
-
- [Fact]
- public void MinimalApiModel_CanBeInstantiated_Net10()
- {
- var model = new MinimalApiModel
- {
- OpenAPI = true,
- UseTypedResults = true,
- EndpointsClassName = "ProductEndpoints",
- EndpointsFileName = "ProductEndpoints.cs",
- EndpointsPath = Path.Combine(_testProjectDir, "ProductEndpoints.cs"),
- EndpointsNamespace = "TestProject",
- EndpointsMethodName = "MapProductEndpoints",
- DbContextInfo = new DbContextInfo { DbContextClassName = "AppDbContext", EfScenario = true },
- ModelInfo = new ModelInfo { ModelTypeName = "Product" },
- ProjectInfo = new ProjectInfo(_testProjectPath)
- };
-
- Assert.NotNull(model);
- Assert.True(model.OpenAPI);
- Assert.True(model.UseTypedResults);
- Assert.Equal("ProductEndpoints", model.EndpointsClassName);
- }
-
- [Fact]
- public void MinimalApiModel_UseTypedResults_DefaultTrue_Net10()
- {
- var model = new MinimalApiModel
- {
- DbContextInfo = new DbContextInfo(),
- ModelInfo = new ModelInfo { ModelTypeName = "Product" },
- ProjectInfo = new ProjectInfo(_testProjectPath)
- };
-
- Assert.True(model.UseTypedResults);
- }
-
- [Fact]
- public void MinimalApiModel_EndpointsMethodName_FollowsNamingConvention_Net10()
- {
- var model = new MinimalApiModel
- {
- EndpointsMethodName = "MapProductEndpoints",
- DbContextInfo = new DbContextInfo(),
- ModelInfo = new ModelInfo { ModelTypeName = "Product" },
- ProjectInfo = new ProjectInfo(_testProjectPath)
- };
-
- Assert.StartsWith("Map", model.EndpointsMethodName);
- Assert.EndsWith("Endpoints", model.EndpointsMethodName);
- }
-
- #endregion
-
- #region MinimalApiSettings Properties
-
- [Fact]
- public void MinimalApiSettings_InheritsFromEfWithModelStepSettings_Net10()
- {
- Assert.True(typeof(MinimalApiSettings).IsSubclassOf(typeof(EfWithModelStepSettings)));
- }
-
- [Fact]
- public void MinimalApiSettings_HasEndpointsProperty_Net10()
- {
- Assert.NotNull(typeof(MinimalApiSettings).GetProperty("Endpoints"));
- }
-
- [Fact]
- public void MinimalApiSettings_HasOpenApiProperty_Net10()
- {
- Assert.NotNull(typeof(MinimalApiSettings).GetProperty("OpenApi"));
- }
-
- [Fact]
- public void MinimalApiSettings_HasTypedResultsProperty_Net10()
- {
- Assert.NotNull(typeof(MinimalApiSettings).GetProperty("TypedResults"));
- }
-
- [Fact]
- public void MinimalApiSettings_OpenApi_DefaultTrue_Net10()
- {
- var settings = new MinimalApiSettings
- {
- Project = _testProjectPath,
- Model = "Product"
- };
-
- Assert.True(settings.OpenApi);
- }
-
- [Fact]
- public void MinimalApiSettings_TypedResults_DefaultTrue_Net10()
- {
- var settings = new MinimalApiSettings
- {
- Project = _testProjectPath,
- Model = "Product"
- };
-
- Assert.True(settings.TypedResults);
- }
-
- [Fact]
- public void MinimalApiSettings_CanSetAllProperties_Net10()
- {
- var settings = new MinimalApiSettings
- {
- Project = _testProjectPath,
- Model = "Product",
- Endpoints = "ProductEndpoints",
- OpenApi = false,
- TypedResults = false,
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer,
- Prerelease = true
- };
-
- Assert.Equal(_testProjectPath, settings.Project);
- Assert.Equal("Product", settings.Model);
- Assert.Equal("ProductEndpoints", settings.Endpoints);
- Assert.False(settings.OpenApi);
- Assert.False(settings.TypedResults);
- Assert.Equal("AppDbContext", settings.DataContext);
- Assert.Equal(PackageConstants.EfConstants.SqlServer, settings.DatabaseProvider);
- Assert.True(settings.Prerelease);
- }
-
- #endregion
-
- #region EfWithModelStepSettings Properties
-
- [Fact]
- public void EfWithModelStepSettings_InheritsFromBaseSettings_Net10()
- {
- Assert.True(typeof(EfWithModelStepSettings).IsSubclassOf(typeof(BaseSettings)));
- }
-
- [Fact]
- public void EfWithModelStepSettings_HasDatabaseProviderProperty_Net10()
- {
- Assert.NotNull(typeof(EfWithModelStepSettings).GetProperty("DatabaseProvider"));
- }
-
- [Fact]
- public void EfWithModelStepSettings_HasDataContextProperty_Net10()
- {
- Assert.NotNull(typeof(EfWithModelStepSettings).GetProperty("DataContext"));
- }
-
- [Fact]
- public void EfWithModelStepSettings_HasModelProperty_Net10()
- {
- Assert.NotNull(typeof(EfWithModelStepSettings).GetProperty("Model"));
- }
-
- [Fact]
- public void EfWithModelStepSettings_HasPrereleaseProperty_Net10()
- {
- Assert.NotNull(typeof(EfWithModelStepSettings).GetProperty("Prerelease"));
- }
-
- #endregion
-
- #region BaseSettings Properties
-
- [Fact]
- public void BaseSettings_HasProjectProperty_Net10()
- {
- Assert.NotNull(typeof(BaseSettings).GetProperty("Project"));
- }
-
- [Fact]
- public void BaseSettings_IsBaseClassForMinimalApiSettings_Net10()
- {
- Assert.True(typeof(MinimalApiSettings).IsSubclassOf(typeof(BaseSettings)));
- }
-
- #endregion
-
- #region DbContextInfo Properties
-
- [Fact]
- public void DbContextInfo_HasDbContextClassNameProperty_Net10()
- {
- Assert.NotNull(typeof(DbContextInfo).GetProperty("DbContextClassName"));
- }
-
- [Fact]
- public void DbContextInfo_HasEfScenarioProperty_Net10()
- {
- Assert.NotNull(typeof(DbContextInfo).GetProperty("EfScenario"));
- }
-
- [Fact]
- public void DbContextInfo_HasDatabaseProviderProperty_Net10()
- {
- Assert.NotNull(typeof(DbContextInfo).GetProperty("DatabaseProvider"));
- }
-
- [Fact]
- public void DbContextInfo_EfScenario_IsSetable_Net10()
- {
- var info = new DbContextInfo();
- info.EfScenario = true;
- Assert.True(info.EfScenario);
- info.EfScenario = false;
- Assert.False(info.EfScenario);
- }
-
- [Fact]
- public void DbContextInfo_CanSetDbContextClassName_Net10()
- {
- var info = new DbContextInfo { DbContextClassName = "AppDbContext" };
- Assert.Equal("AppDbContext", info.DbContextClassName);
- }
-
- #endregion
-
- #region ModelInfo Properties
-
- [Fact]
- public void ModelInfo_HasModelTypeNameProperty_Net10()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("ModelTypeName"));
- }
-
- [Fact]
- public void ModelInfo_HasModelNamespaceProperty_Net10()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("ModelNamespace"));
- }
-
- [Fact]
- public void ModelInfo_HasModelTypePluralNameProperty_Net10()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("ModelTypePluralName"));
- }
-
- [Fact]
- public void ModelInfo_CanSetProperties_Net10()
- {
- var info = new ModelInfo
- {
- ModelTypeName = "Product",
- ModelNamespace = "TestProject.Models"
- };
-
- Assert.Equal("Product", info.ModelTypeName);
- Assert.Equal("TestProject.Models", info.ModelNamespace);
- }
-
- [Fact]
- public void ModelInfo_HasPrimaryKeyNameProperty_Net10()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("PrimaryKeyName"));
- }
-
- [Fact]
- public void ModelInfo_HasPrimaryKeyShortTypeNameProperty_Net10()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("PrimaryKeyShortTypeName"));
- }
-
- [Fact]
- public void ModelInfo_HasPrimaryKeyTypeNameProperty_Net10()
- {
- Assert.NotNull(typeof(ModelInfo).GetProperty("PrimaryKeyTypeName"));
- }
-
- #endregion
-
- #region PackageConstants — EF
-
- [Fact]
- public void EfConstants_SqlServer_HasCorrectValue_Net10()
- {
- Assert.Equal("sqlserver-efcore", PackageConstants.EfConstants.SqlServer);
- }
-
- [Fact]
- public void EfConstants_SQLite_HasCorrectValue_Net10()
- {
- Assert.Equal("sqlite-efcore", PackageConstants.EfConstants.SQLite);
- }
-
- [Fact]
- public void EfConstants_Postgres_HasCorrectValue_Net10()
- {
- Assert.Equal("npgsql-efcore", PackageConstants.EfConstants.Postgres);
- }
-
- [Fact]
- public void EfConstants_CosmosDb_HasCorrectValue_Net10()
- {
- Assert.Equal("cosmos-efcore", PackageConstants.EfConstants.CosmosDb);
- }
-
- [Fact]
- public void EfConstants_EfPackagesDict_ContainsSqlServer_Net10()
- {
- Assert.True(PackageConstants.EfConstants.EfPackagesDict.ContainsKey(PackageConstants.EfConstants.SqlServer));
- }
-
- [Fact]
- public void EfConstants_EfPackagesDict_ContainsSQLite_Net10()
- {
- Assert.True(PackageConstants.EfConstants.EfPackagesDict.ContainsKey(PackageConstants.EfConstants.SQLite));
- }
-
- [Fact]
- public void EfConstants_EfPackagesDict_ContainsPostgres_Net10()
- {
- Assert.True(PackageConstants.EfConstants.EfPackagesDict.ContainsKey(PackageConstants.EfConstants.Postgres));
- }
-
- [Fact]
- public void EfConstants_EfPackagesDict_ContainsCosmosDb_Net10()
- {
- Assert.True(PackageConstants.EfConstants.EfPackagesDict.ContainsKey(PackageConstants.EfConstants.CosmosDb));
- }
-
- [Fact]
- public void EfConstants_EfPackagesDict_HasAtLeast4Providers_Net10()
- {
- Assert.True(PackageConstants.EfConstants.EfPackagesDict.Count >= 4);
- }
-
- [Fact]
- public void EfConstants_SqlServerPackage_HasCorrectName_Net10()
- {
- var package = PackageConstants.EfConstants.EfPackagesDict[PackageConstants.EfConstants.SqlServer];
- Assert.Equal("Microsoft.EntityFrameworkCore.SqlServer", package.Name);
- }
-
- [Fact]
- public void EfConstants_SQLitePackage_HasCorrectName_Net10()
- {
- var package = PackageConstants.EfConstants.EfPackagesDict[PackageConstants.EfConstants.SQLite];
- Assert.Equal("Microsoft.EntityFrameworkCore.Sqlite", package.Name);
- }
-
- [Fact]
- public void EfConstants_PostgresPackage_HasCorrectName_Net10()
- {
- var package = PackageConstants.EfConstants.EfPackagesDict[PackageConstants.EfConstants.Postgres];
- Assert.Equal("Npgsql.EntityFrameworkCore.PostgreSQL", package.Name);
- }
-
- [Fact]
- public void EfConstants_CosmosDbPackage_HasCorrectName_Net10()
- {
- var package = PackageConstants.EfConstants.EfPackagesDict[PackageConstants.EfConstants.CosmosDb];
- Assert.Equal("Microsoft.EntityFrameworkCore.Cosmos", package.Name);
- }
-
- [Fact]
- public void EfConstants_EfCoreToolsPackage_HasCorrectName_Net10()
- {
- Assert.Equal("Microsoft.EntityFrameworkCore.Tools", PackageConstants.EfConstants.EfCoreToolsPackage.Name);
- }
-
- #endregion
-
- #region PackageConstants — OpenAPI
-
- [Fact]
- public void OpenApiPackage_HasCorrectName_Net10()
- {
- Assert.Equal("Microsoft.AspNetCore.OpenApi", PackageConstants.AspNetCorePackages.OpenApiPackage.Name);
- }
-
- [Fact]
- public void OpenApiPackage_IsVersionRequired_Net10()
- {
- Assert.True(PackageConstants.AspNetCorePackages.OpenApiPackage.IsVersionRequired);
- }
-
- #endregion
-
- #region UseDatabaseMethods
-
- [Fact]
- public void UseDatabaseMethods_ContainsSqlServer_Net10()
- {
- var field = typeof(PackageConstants.EfConstants).GetField("UseDatabaseMethods", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
- Assert.NotNull(field);
- }
-
- [Fact]
- public void UseDatabaseMethods_SqlServerMethodName_IsUseSqlServer_Net10()
- {
- Assert.True(PackageConstants.EfConstants.UseDatabaseMethods.ContainsKey(PackageConstants.EfConstants.SqlServer));
- Assert.Equal("UseSqlServer", PackageConstants.EfConstants.UseDatabaseMethods[PackageConstants.EfConstants.SqlServer]);
- }
-
- [Fact]
- public void UseDatabaseMethods_SQLiteMethodName_IsUseSqlite_Net10()
- {
- Assert.True(PackageConstants.EfConstants.UseDatabaseMethods.ContainsKey(PackageConstants.EfConstants.SQLite));
- Assert.Equal("UseSqlite", PackageConstants.EfConstants.UseDatabaseMethods[PackageConstants.EfConstants.SQLite]);
- }
-
- [Fact]
- public void UseDatabaseMethods_PostgresMethodName_IsUseNpgsql_Net10()
- {
- Assert.True(PackageConstants.EfConstants.UseDatabaseMethods.ContainsKey(PackageConstants.EfConstants.Postgres));
- Assert.Equal("UseNpgsql", PackageConstants.EfConstants.UseDatabaseMethods[PackageConstants.EfConstants.Postgres]);
- }
-
- [Fact]
- public void UseDatabaseMethods_CosmosDbMethodName_IsUseCosmos_Net10()
- {
- Assert.True(PackageConstants.EfConstants.UseDatabaseMethods.ContainsKey(PackageConstants.EfConstants.CosmosDb));
- Assert.Equal("UseCosmos", PackageConstants.EfConstants.UseDatabaseMethods[PackageConstants.EfConstants.CosmosDb]);
- }
-
- #endregion
-
- #region Template Folder Verification — Net10 (.tt format)
-
- [Fact]
- public void Net10TemplateFolderContainsMinimalApiTtTemplate_Net10()
- {
- var assembly = typeof(MinimalApiHelper).Assembly;
- string basePath = Path.GetDirectoryName(assembly.Location)!;
- string templatePath = Path.Combine(basePath, "Templates", TargetFramework, "MinimalApi", "MinimalApi.tt");
-
- if (File.Exists(templatePath))
- {
- string content = File.ReadAllText(templatePath);
- Assert.NotEmpty(content);
- }
- else
- {
- // Template may be embedded or packed at build time; verify template types in assembly
- Assert.True(true, ".tt template expected packed from source at build time");
- }
- }
-
- [Fact]
- public void Net10TemplateFolderContainsMinimalApiEfTtTemplate_Net10()
- {
- var assembly = typeof(MinimalApiHelper).Assembly;
- string basePath = Path.GetDirectoryName(assembly.Location)!;
- string templatePath = Path.Combine(basePath, "Templates", TargetFramework, "MinimalApi", "MinimalApiEf.tt");
-
- if (File.Exists(templatePath))
- {
- string content = File.ReadAllText(templatePath);
- Assert.NotEmpty(content);
- }
- else
- {
- Assert.True(true, ".tt template expected packed from source at build time");
- }
- }
-
- [Fact]
- public void Net10TemplateFolderContainsMinimalApiCsFile_Net10()
- {
- var assembly = typeof(MinimalApiHelper).Assembly;
- string basePath = Path.GetDirectoryName(assembly.Location)!;
- string filePath = Path.Combine(basePath, "Templates", TargetFramework, "MinimalApi", "MinimalApi.cs");
-
- if (File.Exists(filePath))
- {
- string content = File.ReadAllText(filePath);
- Assert.NotEmpty(content);
- }
- else
- {
- Assert.True(true, ".cs file expected packed from source at build time");
- }
- }
-
- [Fact]
- public void Net10TemplateFolderContainsMinimalApiInterfacesFile_Net10()
- {
- var assembly = typeof(MinimalApiHelper).Assembly;
- string basePath = Path.GetDirectoryName(assembly.Location)!;
- string filePath = Path.Combine(basePath, "Templates", TargetFramework, "MinimalApi", "MinimalApi.Interfaces.cs");
-
- if (File.Exists(filePath))
- {
- string content = File.ReadAllText(filePath);
- Assert.NotEmpty(content);
- }
- else
- {
- Assert.True(true, ".Interfaces.cs file expected packed from source at build time");
- }
- }
-
- [Fact]
- public void Net10TemplateFolderContainsMinimalApiEfCsFile_Net10()
- {
- var assembly = typeof(MinimalApiHelper).Assembly;
- string basePath = Path.GetDirectoryName(assembly.Location)!;
- string filePath = Path.Combine(basePath, "Templates", TargetFramework, "MinimalApi", "MinimalApiEf.cs");
-
- if (File.Exists(filePath))
- {
- string content = File.ReadAllText(filePath);
- Assert.NotEmpty(content);
- }
- else
- {
- Assert.True(true, ".cs file expected packed from source at build time");
- }
- }
-
- [Fact]
- public void Net10TemplateFolderContainsMinimalApiEfInterfacesFile_Net10()
- {
- var assembly = typeof(MinimalApiHelper).Assembly;
- string basePath = Path.GetDirectoryName(assembly.Location)!;
- string filePath = Path.Combine(basePath, "Templates", TargetFramework, "MinimalApi", "MinimalApiEf.Interfaces.cs");
-
- if (File.Exists(filePath))
- {
- string content = File.ReadAllText(filePath);
- Assert.NotEmpty(content);
- }
- else
- {
- Assert.True(true, ".Interfaces.cs file expected packed from source at build time");
- }
- }
-
- [Fact]
- public void Net10TemplateFolder_HasSixTemplateFiles_Net10()
- {
- // net10.0 MinimalApi folder has 6 files:
- // MinimalApi.cs, MinimalApi.Interfaces.cs, MinimalApi.tt,
- // MinimalApiEf.cs, MinimalApiEf.Interfaces.cs, MinimalApiEf.tt
- var assembly = typeof(MinimalApiHelper).Assembly;
- string basePath = Path.GetDirectoryName(assembly.Location)!;
- string templateDir = Path.Combine(basePath, "Templates", TargetFramework, "MinimalApi");
-
- if (Directory.Exists(templateDir))
- {
- var allFiles = Directory.GetFiles(templateDir);
- Assert.Equal(6, allFiles.Length);
- }
- else
- {
- Assert.True(true, "Template folder may be packed at build time");
- }
- }
-
- [Fact]
- public void Net10TemplateFolder_HasTwoTtTemplates_Net10()
- {
- // net10.0 MinimalApi folder has 2 .tt templates: MinimalApi.tt, MinimalApiEf.tt
- var assembly = typeof(MinimalApiHelper).Assembly;
- string basePath = Path.GetDirectoryName(assembly.Location)!;
- string templateDir = Path.Combine(basePath, "Templates", TargetFramework, "MinimalApi");
-
- if (Directory.Exists(templateDir))
- {
- var ttFiles = Directory.GetFiles(templateDir, "*.tt");
- Assert.Equal(2, ttFiles.Length);
- }
- else
- {
- Assert.True(true, "Template folder may be packed at build time");
- }
- }
-
- [Fact]
- public void Net10TemplateFolder_HasNoCshtmlTemplates_Net10()
- {
- // net10.0 uses .tt format, NOT .cshtml (unlike net8.0)
- var assembly = typeof(MinimalApiHelper).Assembly;
- string basePath = Path.GetDirectoryName(assembly.Location)!;
- string templateDir = Path.Combine(basePath, "Templates", TargetFramework, "MinimalApi");
-
- if (Directory.Exists(templateDir))
- {
- var cshtmlFiles = Directory.GetFiles(templateDir, "*.cshtml");
- Assert.Empty(cshtmlFiles);
- }
- else
- {
- Assert.True(true, "Template folder may be packed at build time");
- }
- }
-
- #endregion
-
- #region Net10 .cs Template Compilation Exclusion
-
- [Fact]
- public void Net10CsTemplateFiles_AreExcludedFromCompilation_Net10()
- {
- // net10.0 .cs files are excluded via
- // The compiled types are provided by the net11.0 folder .cs files (NOT excluded)
- // which also use the Templates.net10.MinimalApi namespace
- var assembly = typeof(MinimalApiHelper).Assembly;
- var allTypes = assembly.GetTypes();
-
- // Compiled types should exist in Templates.net10.MinimalApi namespace (from net11.0 folder)
- var net10MinimalApiTypes = allTypes.Where(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.MinimalApi")).ToList();
-
- Assert.True(net10MinimalApiTypes.Count > 0,
- "Expected compiled MinimalApi template types in Templates.net10.MinimalApi namespace (provided by net11.0 folder)");
- }
-
- [Fact]
- public void Net10TemplateTypes_InNet10Namespace_Net10()
- {
- // The canonical namespace for MinimalApi compiled types is Templates.net10.MinimalApi
- // These are compiled from net11.0 folder .cs files which share the same namespace
- var assembly = typeof(MinimalApiHelper).Assembly;
- var allTypes = assembly.GetTypes();
- var net10Types = allTypes.Where(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.MinimalApi")).ToList();
-
- Assert.True(net10Types.Count > 0,
- "Expected compiled MinimalApi template types in Templates.net10.MinimalApi namespace");
- }
-
- [Fact]
- public void Net10SourceCsFiles_UseNet10Namespace_Net10()
- {
- // Verify the source .cs files in net10.0 folder define types in Templates.net10.MinimalApi namespace
- var assembly = typeof(MinimalApiHelper).Assembly;
- string basePath = Path.GetDirectoryName(assembly.Location)!;
- string csFilePath = Path.Combine(basePath, "Templates", TargetFramework, "MinimalApi", "MinimalApi.cs");
-
- if (File.Exists(csFilePath))
- {
- string content = File.ReadAllText(csFilePath);
- Assert.Contains("Templates.net10.MinimalApi", content);
- }
- else
- {
- // Even though the .cs files are excluded from compilation, they exist on disk
- Assert.True(true, "Source .cs file expected packed from source at build time");
- }
- }
-
- [Fact]
- public void Net10TemplateFormat_UsesTtNotCshtml_Net10()
- {
- // net10.0 uses .tt text-templating format (same as net9.0, unlike net8.0 .cshtml)
- Assert.Equal(".tt", AspNetConstants.T4TemplateExtension);
-
- // Compiled template types exist in net10 namespace
- var assembly = typeof(MinimalApiHelper).Assembly;
- var allTypes = assembly.GetTypes();
- var minimalApiType = allTypes.FirstOrDefault(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.MinimalApi.MinimalApi"));
-
- Assert.NotNull(minimalApiType);
- }
-
- #endregion
-
- #region MinimalApiHelper Template Type Resolution
-
- [Fact]
- public void MinimalApiHelper_TemplateTypes_AreResolvableFromAssembly_Net10()
- {
- var assembly = typeof(MinimalApiHelper).Assembly;
- var allTypes = assembly.GetTypes();
- var minimalApiTypes = allTypes.Where(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.MinimalApi")).ToList();
-
- Assert.True(minimalApiTypes.Count > 0, "Expected MinimalApi template types in assembly");
- }
-
- [Fact]
- public void MinimalApiHelper_MinimalApi_TemplateTypeExists_Net10()
- {
- var assembly = typeof(MinimalApiHelper).Assembly;
- var allTypes = assembly.GetTypes();
- var minimalApiType = allTypes.FirstOrDefault(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.MinimalApi") &&
- t.Name.Equals("MinimalApi", StringComparison.OrdinalIgnoreCase));
-
- Assert.NotNull(minimalApiType);
- }
-
- [Fact]
- public void MinimalApiHelper_MinimalApiEf_TemplateTypeExists_Net10()
- {
- var assembly = typeof(MinimalApiHelper).Assembly;
- var allTypes = assembly.GetTypes();
- var minimalApiEfType = allTypes.FirstOrDefault(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.MinimalApi") &&
- t.Name.Equals("MinimalApiEf", StringComparison.OrdinalIgnoreCase));
-
- Assert.NotNull(minimalApiEfType);
- }
-
- [Fact]
- public void MinimalApiHelper_ThrowsWhenProjectInfoNull_Net10()
- {
- var model = new MinimalApiModel
- {
- OpenAPI = true,
- UseTypedResults = true,
- EndpointsClassName = "ProductEndpoints",
- EndpointsFileName = "ProductEndpoints.cs",
- EndpointsPath = Path.Combine(_testProjectDir, "ProductEndpoints.cs"),
- EndpointsNamespace = "TestProject",
- EndpointsMethodName = "MapProductEndpoints",
- DbContextInfo = new DbContextInfo { DbContextClassName = "AppDbContext", EfScenario = true },
- ModelInfo = new ModelInfo { ModelTypeName = "Product" },
- ProjectInfo = new ProjectInfo(null)
- };
-
- Assert.Throws(() =>
- MinimalApiHelper.GetMinimalApiTemplatingProperty(model));
- }
-
- [Fact]
- public void MinimalApiHelper_GetMinimalApiTemplatingProperty_MethodExists_Net10()
- {
- var method = typeof(MinimalApiHelper).GetMethod("GetMinimalApiTemplatingProperty",
- BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
- Assert.NotNull(method);
- }
-
- #endregion
-
- #region Code Modification Configs
-
- [Fact]
- public void Net10CodeModificationConfig_MinimalApiChanges_Exists_Net10()
- {
- // The code currently hardcodes net11.0 for the targetFrameworkFolder
- var assembly = typeof(MinimalApiHelper).Assembly;
- string basePath = Path.GetDirectoryName(assembly.Location)!;
- string configPath = Path.Combine(basePath, "Templates", "net11.0", "CodeModificationConfigs", "minimalApiChanges.json");
-
- if (File.Exists(configPath))
- {
- string content = File.ReadAllText(configPath);
- Assert.Contains("Program.cs", content);
- }
- else
- {
- Assert.True(true, "Config file expected embedded in assembly");
- }
- }
-
- [Fact]
- public void Net10CodeModificationConfig_MinimalApiChanges_SourceExists_Net10()
- {
- // Verify the source minimalApiChanges.json exists for net10.0
- var assembly = typeof(MinimalApiHelper).Assembly;
- string basePath = Path.GetDirectoryName(assembly.Location)!;
- string configPath = Path.Combine(basePath, "Templates", TargetFramework, "CodeModificationConfigs", "minimalApiChanges.json");
-
- if (File.Exists(configPath))
- {
- string content = File.ReadAllText(configPath);
- Assert.Contains("Program.cs", content);
- }
- else
- {
- Assert.True(true, "Config file expected embedded in assembly at build time");
- }
- }
-
- #endregion
-
- #region Pipeline Step Sequence
-
- [Fact]
- public void MinimalApiPipeline_DefinesCorrectStepSequence_Net10()
- {
- Assert.NotNull(typeof(ValidateMinimalApiStep));
- Assert.True(typeof(ValidateMinimalApiStep).IsClass);
- }
-
- [Fact]
- public void MinimalApiPipeline_AllKeyStepsInheritFromScaffoldStep_Net10()
- {
- Assert.True(typeof(ValidateMinimalApiStep).IsAssignableTo(typeof(ScaffoldStep)));
- }
-
- [Fact]
- public void MinimalApiPipeline_AllKeyStepsAreInScaffoldStepsNamespace_Net10()
- {
- string expectedNs = "Microsoft.DotNet.Tools.Scaffold.AspNet.ScaffoldSteps";
- Assert.Equal(expectedNs, typeof(ValidateMinimalApiStep).Namespace);
- }
-
- [Fact]
- public void MinimalApiPipeline_HasSixSteps_Net10()
- {
- // Pipeline: ValidateMinimalApiStep → AddPackages → DbContext → ConnectionString → TextTemplating → CodeChange
- Assert.True(true, "Pipeline has 6 steps including validation, AddPackages, DbContext, ConnectionString, TextTemplating, CodeChange");
- }
-
- #endregion
-
- #region Builder Extensions
-
- [Fact]
- public void MinimalApiBuilderExtensions_WithMinimalApiTextTemplatingStep_Exists_Net10()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.MinimalApiScaffolderBuilderExtensions);
- var method = extensionType.GetMethod("WithMinimalApiTextTemplatingStep", BindingFlags.Public | BindingFlags.Static);
- Assert.NotNull(method);
- }
-
- [Fact]
- public void MinimalApiBuilderExtensions_WithMinimalApiAddPackagesStep_Exists_Net10()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.MinimalApiScaffolderBuilderExtensions);
- var method = extensionType.GetMethod("WithMinimalApiAddPackagesStep", BindingFlags.Public | BindingFlags.Static);
- Assert.NotNull(method);
- }
-
- [Fact]
- public void MinimalApiBuilderExtensions_WithMinimalApiCodeChangeStep_Exists_Net10()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.MinimalApiScaffolderBuilderExtensions);
- var method = extensionType.GetMethod("WithMinimalApiCodeChangeStep", BindingFlags.Public | BindingFlags.Static);
- Assert.NotNull(method);
- }
-
- [Fact]
- public void MinimalApiBuilderExtensions_Has3ExtensionMethods_Net10()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.MinimalApiScaffolderBuilderExtensions);
- var methods = extensionType.GetMethods(BindingFlags.Public | BindingFlags.Static)
- .Where(m => m.GetParameters().Any(p => p.ParameterType == typeof(IScaffoldBuilder)))
- .ToList();
- Assert.Equal(3, methods.Count);
- }
-
- [Fact]
- public void MinimalApiBuilderExtensions_AllMethodsReturnIScaffoldBuilder_Net10()
- {
- var extensionType = typeof(Scaffolding.Core.Hosting.MinimalApiScaffolderBuilderExtensions);
- var methods = extensionType.GetMethods(BindingFlags.Public | BindingFlags.Static)
- .Where(m => m.GetParameters().Any(p => p.ParameterType == typeof(IScaffoldBuilder)))
- .ToList();
-
- foreach (var method in methods)
- {
- Assert.Equal(typeof(IScaffoldBuilder), method.ReturnType);
- }
- }
-
- #endregion
-
- #region TFM Availability
-
- [Fact]
- public void MinimalApi_IsAvailableForNet10_Net10()
- {
- Assert.Equal("API", AspnetStrings.Catagories.API);
- }
-
- [Fact]
- public void CommandInfoExtensions_IsCommandAnAspNetCommand_Exists_Net10()
- {
- var method = typeof(CommandInfoExtensions).GetMethod("IsCommandAnAspNetCommand");
- Assert.NotNull(method);
- }
-
- [Fact]
- public void MinimalApi_Net10UsesTtTemplatesNotCshtml_Net10()
- {
- // net10.0 uses .tt text-templating format, same as net9.0
- var assembly = typeof(MinimalApiHelper).Assembly;
- string basePath = Path.GetDirectoryName(assembly.Location)!;
- string net10Dir = Path.Combine(basePath, "Templates", TargetFramework, "MinimalApi");
-
- if (Directory.Exists(net10Dir))
- {
- var net10TtTemplates = Directory.GetFiles(net10Dir, "*.tt");
- Assert.True(net10TtTemplates.Length > 0 || true, "Net10 uses .tt format or templates packed at build time");
-
- // Ensure no .cshtml files in net10 folder
- var net10CshtmlTemplates = Directory.GetFiles(net10Dir, "*.cshtml");
- Assert.Empty(net10CshtmlTemplates);
- }
- else
- {
- Assert.True(true, "Template directories may be packed at build time");
- }
- }
-
- [Fact]
- public void MinimalApi_Net10IsCanonicalTemplateNamespace_Net10()
- {
- // Templates.net10.MinimalApi is the canonical compiled namespace used by MinimalApiHelper
- // The types are compiled from net11.0 folder .cs files (net10.0 .cs files are excluded)
- var assembly = typeof(MinimalApiHelper).Assembly;
- var allTypes = assembly.GetTypes();
- var net10MinimalApiType = allTypes.FirstOrDefault(t =>
- !string.IsNullOrEmpty(t.FullName) &&
- t.FullName.Contains("Templates.net10.MinimalApi") &&
- t.Name == "MinimalApi");
-
- Assert.NotNull(net10MinimalApiType);
- }
-
- #endregion
-
- #region Cancellation Support
-
- [Fact]
- public async Task ValidateMinimalApiStep_AcceptsCancellationToken_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- Endpoints = "ProductEndpoints"
- };
-
- using var cts = new CancellationTokenSource();
- bool result = await step.ExecuteAsync(_context, cts.Token);
-
- Assert.False(result);
- }
-
- [Fact]
- public void ValidateMinimalApiStep_ExecuteAsync_IsInherited_Net10()
- {
- var method = typeof(ValidateMinimalApiStep).GetMethod("ExecuteAsync", new[] { typeof(ScaffolderContext), typeof(CancellationToken) });
- Assert.NotNull(method);
- Assert.True(method!.IsVirtual);
- }
-
- #endregion
-
- #region Scaffolder Registration Constants
-
- [Fact]
- public void MinimalApi_UsesCorrectName_Net10()
- {
- Assert.Equal("minimalapi", AspnetStrings.Api.MinimalApi);
- }
-
- [Fact]
- public void MinimalApi_UsesCorrectDisplayName_Net10()
- {
- Assert.Equal("Minimal API", AspnetStrings.Api.MinimalApiDisplayName);
- }
-
- [Fact]
- public void MinimalApi_UsesCorrectCategory_Net10()
- {
- Assert.Equal("API", AspnetStrings.Catagories.API);
- }
-
- [Fact]
- public void MinimalApi_UsesCorrectDescription_Net10()
- {
- Assert.Equal("Generates an endpoints file (with CRUD API endpoints) given a model and optional DbContext.", AspnetStrings.Api.MinimalApiDescription);
- }
-
- [Fact]
- public void MinimalApi_Has2Examples_Net10()
- {
- Assert.NotEmpty(AspnetStrings.Api.MinimalApiExample1);
- Assert.NotEmpty(AspnetStrings.Api.MinimalApiExample2);
- Assert.NotEmpty(AspnetStrings.Api.MinimalApiExample1Description);
- Assert.NotEmpty(AspnetStrings.Api.MinimalApiExample2Description);
- }
-
- #endregion
-
- #region Scaffolding Context Properties
-
- [Fact]
- public void ScaffolderContext_CanStoreMinimalApiModel_Net10()
- {
- var model = new MinimalApiModel
- {
- OpenAPI = true,
- UseTypedResults = true,
- EndpointsClassName = "ProductEndpoints",
- EndpointsFileName = "ProductEndpoints.cs",
- EndpointsPath = Path.Combine(_testProjectDir, "ProductEndpoints.cs"),
- EndpointsNamespace = "TestProject",
- EndpointsMethodName = "MapProductEndpoints",
- DbContextInfo = new DbContextInfo { DbContextClassName = "AppDbContext", EfScenario = true },
- ModelInfo = new ModelInfo { ModelTypeName = "Product" },
- ProjectInfo = new ProjectInfo(_testProjectPath)
- };
-
- _context.Properties.Add(nameof(MinimalApiModel), model);
-
- Assert.True(_context.Properties.ContainsKey(nameof(MinimalApiModel)));
- var retrieved = _context.Properties[nameof(MinimalApiModel)] as MinimalApiModel;
- Assert.NotNull(retrieved);
- Assert.True(retrieved!.OpenAPI);
- Assert.True(retrieved.UseTypedResults);
- Assert.Equal("ProductEndpoints", retrieved.EndpointsClassName);
- Assert.Equal("Product", retrieved.ModelInfo.ModelTypeName);
- Assert.True(retrieved.DbContextInfo.EfScenario);
- }
-
- [Fact]
- public void ScaffolderContext_CanStoreMinimalApiSettings_Net10()
- {
- var settings = new MinimalApiSettings
- {
- Project = _testProjectPath,
- Model = "Product",
- Endpoints = "ProductEndpoints",
- OpenApi = true,
- TypedResults = true,
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer,
- Prerelease = false
- };
-
- _context.Properties.Add(nameof(MinimalApiSettings), settings);
-
- Assert.True(_context.Properties.ContainsKey(nameof(MinimalApiSettings)));
- var retrieved = _context.Properties[nameof(MinimalApiSettings)] as MinimalApiSettings;
- Assert.NotNull(retrieved);
- Assert.Equal(_testProjectPath, retrieved!.Project);
- Assert.Equal("Product", retrieved.Model);
- Assert.Equal("ProductEndpoints", retrieved.Endpoints);
- Assert.True(retrieved.OpenApi);
- }
-
- [Fact]
- public void ScaffolderContext_CanStoreCodeModifierProperties_Net10()
- {
- var codeModifierProperties = new Dictionary
- {
- { "EndpointsMethodName", "MapProductEndpoints" },
- { "DbContextName", "AppDbContext" }
- };
-
- _context.Properties.Add(Scaffolding.Internal.Constants.StepConstants.CodeModifierProperties, codeModifierProperties);
-
- Assert.True(_context.Properties.ContainsKey(Scaffolding.Internal.Constants.StepConstants.CodeModifierProperties));
- var retrieved = _context.Properties[Scaffolding.Internal.Constants.StepConstants.CodeModifierProperties] as Dictionary;
- Assert.NotNull(retrieved);
- Assert.Equal(2, retrieved!.Count);
- Assert.Equal("MapProductEndpoints", retrieved["EndpointsMethodName"]);
- }
-
- #endregion
-
- #region NewDbContext Constant
-
- [Fact]
- public void NewDbContext_HasCorrectValue_Net10()
- {
- Assert.Equal("NewDbContext", AspNetConstants.NewDbContext);
- }
-
- #endregion
-
- #region File Extensions
-
- [Fact]
- public void CSharpExtension_IsCorrect_Net10()
- {
- Assert.Equal(".cs", AspNetConstants.CSharpExtension);
- }
-
- [Fact]
- public void T4TemplateExtension_IsCorrect_Net10()
- {
- Assert.Equal(".tt", AspNetConstants.T4TemplateExtension);
- }
-
- #endregion
-
- #region Validation Combination Tests
-
- [Fact]
- public async Task ValidateMinimalApiStep_ValidProjectAndModel_PassesSettingsValidation_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- Endpoints = "ProductEndpoints",
- OpenApi = true,
- TypedResults = true,
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- try
- {
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
- Assert.False(result);
- }
- catch (Exception)
- {
- // Expected - project can't be analyzed since it doesn't exist on disk
- }
-
- Assert.True(_testTelemetryService.TrackedEvents.Count >= 1 || true);
- }
-
- [Fact]
- public async Task ValidateMinimalApiStep_InvalidDbContextName_UsesDefault_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- Endpoints = "ProductEndpoints",
- DataContext = "DbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- try
- {
- await step.ExecuteAsync(_context, CancellationToken.None);
- }
- catch (Exception)
- {
- // Expected - project can't be analyzed
- }
-
- Assert.True(_testTelemetryService.TrackedEvents.Count >= 1 || true);
- }
-
- [Fact]
- public async Task ValidateMinimalApiStep_NullDataContext_NoEfScenario_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- Endpoints = "ProductEndpoints",
- DataContext = null,
- DatabaseProvider = null
- };
-
- try
- {
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
- Assert.False(result);
- }
- catch (Exception)
- {
- // Expected - project can't be analyzed
- }
- }
-
- [Fact]
- public async Task ValidateMinimalApiStep_EmptyDataContext_NoEfScenario_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- Endpoints = "ProductEndpoints",
- DataContext = string.Empty,
- DatabaseProvider = null
- };
-
- try
- {
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
- Assert.False(result);
- }
- catch (Exception)
- {
- // Expected - project can't be analyzed
- }
- }
-
- [Fact]
- public async Task ValidateMinimalApiStep_InvalidDatabaseProvider_DefaultsToSqlServer_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- Endpoints = "ProductEndpoints",
- DataContext = "AppDbContext",
- DatabaseProvider = "InvalidProvider"
- };
-
- try
- {
- await step.ExecuteAsync(_context, CancellationToken.None);
- }
- catch (Exception)
- {
- // Expected - project can't be analyzed
- }
-
- Assert.True(_testTelemetryService.TrackedEvents.Count >= 1 || true);
- }
-
- [Fact]
- public async Task ValidateMinimalApiStep_OpenApiFalse_SettingsPreserved_Net10()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- Endpoints = "ProductEndpoints",
- OpenApi = false,
- TypedResults = false
- };
-
- Assert.False(step.OpenApi);
- Assert.False(step.TypedResults);
- }
-
- #endregion
-
- #region Regression Guards
-
- [Fact]
- public void MinimalApiModel_IsInModelsNamespace_Net10()
- {
- Assert.Equal("Microsoft.DotNet.Tools.Scaffold.AspNet.Models", typeof(MinimalApiModel).Namespace);
- }
-
- [Fact]
- public void MinimalApiSettings_IsInSettingsNamespace_Net10()
- {
- Assert.Equal("Microsoft.DotNet.Tools.Scaffold.AspNet.ScaffoldSteps.Settings", typeof(MinimalApiSettings).Namespace);
- }
-
- [Fact]
- public void MinimalApiHelper_IsInHelpersNamespace_Net10()
- {
- Assert.Equal("Microsoft.DotNet.Tools.Scaffold.AspNet.Helpers", typeof(MinimalApiHelper).Namespace);
- }
-
- [Fact]
- public void ValidateMinimalApiStep_IsInternal_Net10()
- {
- Assert.False(typeof(ValidateMinimalApiStep).IsPublic);
- }
-
- [Fact]
- public void MinimalApiModel_IsInternal_Net10()
- {
- Assert.False(typeof(MinimalApiModel).IsPublic);
- }
-
- [Fact]
- public void MinimalApiSettings_IsInternal_Net10()
- {
- Assert.False(typeof(MinimalApiSettings).IsPublic);
+ protected override string TargetFramework => "net10.0";
+ protected override string TestClassName => nameof(MinimalApiNet10IntegrationTests);
+
+ [Fact]
+ public async Task Scaffold_MinimalApi_Net10_CliInvocation()
+ {
+ // Arrange — set up project with Program.cs and a model class
+ File.WriteAllText(_testProjectPath, ProjectContent);
+ File.WriteAllText(Path.Combine(_testProjectDir, "Program.cs"), ScaffoldCliHelper.GetMinimalProgramCs());
+ var modelsDir = Path.Combine(_testProjectDir, "Models");
+ Directory.CreateDirectory(modelsDir);
+ File.WriteAllText(Path.Combine(modelsDir, "TestModel.cs"), ScaffoldCliHelper.GetModelClassContent("TestProject", "TestModel"));
+
+ // Verify project builds before scaffolding
+ var (beforeExitCode, _, beforeError) = await RunBuildAsync(_testProjectDir);
+ Assert.True(beforeExitCode == 0, $"Project should build before scaffolding. Error: {beforeError}");
+
+ // Act — invoke CLI: dotnet scaffold aspnet minimalapi
+ var (cliExitCode, cliOutput, cliError) = await ScaffoldCliHelper.RunScaffoldAsync(
+ TargetFramework,
+ "minimalapi",
+ "--project", _testProjectPath,
+ "--model", "TestModel",
+ "--endpoints", "TestModelEndpoints",
+ "--dataContext", "TestDbContext",
+ "--dbProvider", "sqlite-efcore");
+ Assert.True(cliExitCode == 0, $"CLI scaffold should succeed.\nOutput: {cliOutput}\nError: {cliError}");
+
+ // Assert — expected files were created
+ Assert.True(File.Exists(Path.Combine(_testProjectDir, "TestModelEndpoints.cs")),
+ "Endpoints file 'TestModelEndpoints.cs' should be created.");
+ Assert.True(File.Exists(Path.Combine(_testProjectDir, "Data", "TestDbContext.cs")),
+ "DbContext file 'Data/TestDbContext.cs' should be created.");
+ var programContent = File.ReadAllText(Path.Combine(_testProjectDir, "Program.cs"));
+ Assert.Contains("TestDbContext", programContent);
+
+ // Assert — no NuGet errors and project builds after scaffolding
+ Assert.False(cliOutput.Contains("error: NU"),
+ $"Scaffolding should not produce NuGet errors for {TargetFramework}.\nOutput: {cliOutput}");
+ var (afterExitCode, _, afterError) = await RunBuildAsync(_testProjectDir);
+ Assert.True(afterExitCode == 0, $"Project should still build after scaffolding. Error: {afterError}");
}
-
- [Fact]
- public void MinimalApiScaffolderBuilderExtensions_IsInternal_Net10()
- {
- Assert.False(typeof(Scaffolding.Core.Hosting.MinimalApiScaffolderBuilderExtensions).IsPublic);
- }
-
- [Fact]
- public void MinimalApiHelper_IsInternal_Net10()
- {
- Assert.False(typeof(MinimalApiHelper).IsPublic);
- }
-
- [Fact]
- public void MinimalApiHelper_IsStatic_Net10()
- {
- Assert.True(typeof(MinimalApiHelper).IsAbstract && typeof(MinimalApiHelper).IsSealed);
- }
-
- [Fact]
- public void DbContextInfo_IsInternal_Net10()
- {
- Assert.False(typeof(DbContextInfo).IsPublic);
- }
-
- [Fact]
- public void ModelInfo_IsInternal_Net10()
- {
- Assert.False(typeof(ModelInfo).IsPublic);
- }
-
- #endregion
-
- #region OpenAPI and TypedResults Option Strings
-
- [Fact]
- public void OpenApiOption_DisplayName_Net10()
- {
- Assert.Equal("Open API Enabled", AspnetStrings.Options.OpenApi.DisplayName);
- }
-
- [Fact]
- public void OpenApiOption_Description_MentionsSwagger_Net10()
- {
- Assert.Contains("OpenAPI", AspnetStrings.Options.OpenApi.Description);
- }
-
- [Fact]
- public void TypedResultsOption_DisplayName_Net10()
- {
- Assert.Equal("Use Typed Results?", AspnetStrings.Options.TypedResults.DisplayName);
- }
-
- [Fact]
- public void TypedResultsOption_Description_MentionsTypedResults_Net10()
- {
- Assert.Contains("TypedResults", AspnetStrings.Options.TypedResults.Description);
- }
-
- [Fact]
- public void EndpointsClassOption_DisplayName_Net10()
- {
- Assert.Equal("Endpoints File Name", AspnetStrings.Options.EndpointsClass.DisplayName);
- }
-
- [Fact]
- public void EndpointsClassOption_Description_MentionsCRUD_Net10()
- {
- Assert.Contains("CRUD", AspnetStrings.Options.EndpointsClass.Description);
- }
-
- #endregion
-
- #region MinimalApi vs ApiController Distinction
-
- [Fact]
- public void MinimalApi_Name_DiffersFromApiController_Net10()
- {
- Assert.NotEqual(AspnetStrings.Api.MinimalApi, AspnetStrings.Api.ApiController);
- Assert.NotEqual(AspnetStrings.Api.MinimalApi, AspnetStrings.Api.ApiControllerCrud);
- }
-
- [Fact]
- public void MinimalApi_DisplayName_DiffersFromApiController_Net10()
- {
- Assert.NotEqual(AspnetStrings.Api.MinimalApiDisplayName, AspnetStrings.Api.ApiControllerDisplayName);
- Assert.NotEqual(AspnetStrings.Api.MinimalApiDisplayName, AspnetStrings.Api.ApiControllerCrudDisplayName);
- }
-
- [Fact]
- public void MinimalApi_SharesApiCategory_WithApiController_Net10()
- {
- Assert.Equal("API", AspnetStrings.Catagories.API);
- }
-
- [Fact]
- public void MinimalApi_HasEndpointsOption_WhileApiControllerHasControllerOption_Net10()
- {
- Assert.Equal("--endpoints", AspNetConstants.CliOptions.EndpointsOption);
- Assert.Equal("--controller", AspNetConstants.CliOptions.ControllerNameOption);
- }
-
- #endregion
-
- #region Non-EF Scenario Tests
-
- [Fact]
- public void MinimalApiModel_SupportsNonEfScenario_Net10()
- {
- var model = new MinimalApiModel
- {
- OpenAPI = true,
- UseTypedResults = true,
- EndpointsClassName = "ProductEndpoints",
- EndpointsFileName = "ProductEndpoints.cs",
- EndpointsPath = Path.Combine(_testProjectDir, "ProductEndpoints.cs"),
- EndpointsNamespace = "TestProject",
- EndpointsMethodName = "MapProductEndpoints",
- DbContextInfo = new DbContextInfo { EfScenario = false },
- ModelInfo = new ModelInfo { ModelTypeName = "Product" },
- ProjectInfo = new ProjectInfo(_testProjectPath)
- };
-
- Assert.False(model.DbContextInfo.EfScenario);
- }
-
- [Fact]
- public void MinimalApiModel_SupportsEfScenario_Net10()
- {
- var model = new MinimalApiModel
- {
- OpenAPI = true,
- UseTypedResults = true,
- EndpointsClassName = "ProductEndpoints",
- EndpointsFileName = "ProductEndpoints.cs",
- EndpointsPath = Path.Combine(_testProjectDir, "ProductEndpoints.cs"),
- EndpointsNamespace = "TestProject",
- EndpointsMethodName = "MapProductEndpoints",
- DbContextInfo = new DbContextInfo { DbContextClassName = "AppDbContext", EfScenario = true },
- ModelInfo = new ModelInfo { ModelTypeName = "Product" },
- ProjectInfo = new ProjectInfo(_testProjectPath)
- };
-
- Assert.True(model.DbContextInfo.EfScenario);
- Assert.Equal("AppDbContext", model.DbContextInfo.DbContextClassName);
- }
-
- [Fact]
- public void MinimalApiSettings_SupportsNullDataContext_Net10()
- {
- var settings = new MinimalApiSettings
- {
- Project = _testProjectPath,
- Model = "Product",
- Endpoints = "ProductEndpoints",
- DataContext = null,
- DatabaseProvider = null
- };
-
- Assert.Null(settings.DataContext);
- Assert.Null(settings.DatabaseProvider);
- }
-
- #endregion
-
- #region CodeChangeOptions Tests
-
- [Fact]
- public void MinimalApiModel_ProjectInfo_CodeChangeOptions_CanBeSet_Net10()
- {
- var projectInfo = new ProjectInfo(_testProjectPath);
- projectInfo.CodeChangeOptions = new[] { "EfScenario", "OpenApi" };
-
- Assert.NotNull(projectInfo.CodeChangeOptions);
- Assert.Contains("EfScenario", projectInfo.CodeChangeOptions);
- Assert.Contains("OpenApi", projectInfo.CodeChangeOptions);
- }
-
- [Fact]
- public void MinimalApiModel_CodeChangeOptions_EfScenarioMeansEfEnabled_Net10()
- {
- var options = new[] { "EfScenario", "OpenApi" };
- Assert.Contains("EfScenario", options);
- }
-
- [Fact]
- public void MinimalApiModel_CodeChangeOptions_EmptyWhenNoEf_Net10()
- {
- var options = new[] { string.Empty, "OpenApi" };
- Assert.Contains(string.Empty, options);
- }
-
- #endregion
-
- #region EndpointsMethodName Convention Tests
-
- [Fact]
- public void EndpointsMethodName_StartsWithMap_Net10()
- {
- string modelName = "Product";
- string expectedMethodName = $"Map{modelName}Endpoints";
- Assert.Equal("MapProductEndpoints", expectedMethodName);
- }
-
- [Fact]
- public void EndpointsFileName_DefaultsToModelEndpoints_Net10()
- {
- string modelName = "Product";
- string expectedFileName = $"{modelName}Endpoints.cs";
- Assert.Equal("ProductEndpoints.cs", expectedFileName);
- }
-
- [Fact]
- public void EndpointsClassName_DefaultsToModelEndpoints_Net10()
- {
- string modelName = "Product";
- string expectedClassName = $"{modelName}Endpoints";
- Assert.Equal("ProductEndpoints", expectedClassName);
- }
-
- #endregion
-
- #region AspNetCorePackages Tests
-
- [Fact]
- public void AspNetCorePackages_QuickGridEfAdapterPackage_Exists_Net10()
- {
- Assert.NotNull(PackageConstants.AspNetCorePackages.QuickGridEfAdapterPackage);
- Assert.Equal("Microsoft.AspNetCore.Components.QuickGrid.EntityFrameworkAdapter", PackageConstants.AspNetCorePackages.QuickGridEfAdapterPackage.Name);
- }
-
- [Fact]
- public void AspNetCorePackages_DiagnosticsEfCorePackage_Exists_Net10()
- {
- Assert.NotNull(PackageConstants.AspNetCorePackages.AspNetCoreDiagnosticsEfCorePackage);
- Assert.Equal("Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore", PackageConstants.AspNetCorePackages.AspNetCoreDiagnosticsEfCorePackage.Name);
- }
-
- #endregion
-
- #region TestTelemetryService Helper
-
- private class TestTelemetryService : ITelemetryService
- {
- public List<(string EventName, IReadOnlyDictionary Properties, IReadOnlyDictionary Measurements)> TrackedEvents { get; } = new();
-
- public void TrackEvent(string eventName, IReadOnlyDictionary properties, IReadOnlyDictionary measurements)
- {
- TrackedEvents.Add((eventName, properties, measurements));
- }
-
- public void Flush()
- {
- }
- }
-
- #endregion
}
diff --git a/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/MinimalApiNet11IntegrationTests.cs b/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/MinimalApiNet11IntegrationTests.cs
index 77fca47c0..3ed3dd780 100644
--- a/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/MinimalApiNet11IntegrationTests.cs
+++ b/test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/API/MinimalApiNet11IntegrationTests.cs
@@ -1,2379 +1,64 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System;
-using System.Collections.Generic;
using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Threading;
using System.Threading.Tasks;
-using Microsoft.DotNet.Scaffolding.Core.Builder;
-using Microsoft.DotNet.Scaffolding.Core.ComponentModel;
-using Microsoft.DotNet.Scaffolding.Core.Scaffolders;
-using Microsoft.DotNet.Scaffolding.Core.Steps;
-using Microsoft.DotNet.Scaffolding.Internal.Services;
-using Microsoft.DotNet.Scaffolding.Internal.Telemetry;
-using Microsoft.DotNet.Scaffolding.TextTemplating;
-using Microsoft.DotNet.Tools.Scaffold.AspNet;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.Commands;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.Common;
-using AspNetConstants = Microsoft.DotNet.Tools.Scaffold.AspNet.Common.Constants;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.Helpers;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.Models;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.ScaffoldSteps;
-using Microsoft.DotNet.Tools.Scaffold.AspNet.ScaffoldSteps.Settings;
-using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Logging.Abstractions;
-using Moq;
+using Microsoft.DotNet.Tools.Scaffold.Tests.Helpers;
using Xunit;
namespace Microsoft.DotNet.Tools.Scaffold.Tests.AspNet.Integration.API;
-///
-/// Integration tests for the Minimal API (minimalapi) scaffolder targeting .NET 11.
-/// Validates scaffolder definition constants, ValidateMinimalApiStep validation logic,
-/// MinimalApiModel/MinimalApiSettings/EfWithModelStepSettings/BaseSettings properties,
-/// MinimalApiHelper template resolution, template folder verification, code modification configs,
-/// package constants, pipeline registration, step dependencies, telemetry tracking,
-/// TFM availability, builder extensions, OpenAPI and TypedResults support,
-/// and database provider support.
-/// .NET 11 MinimalApi templates use the .tt text-templating format (MinimalApi.tt, MinimalApiEf.tt)
-/// with accompanying .cs and .Interfaces.cs generated files. The net11.0 .cs files are the ones
-/// actually compiled (unlike net8.0/net9.0/net10.0 which are excluded via <Compile Remove>).
-/// The compiled template types use the Templates.net10.MinimalApi namespace. The net11.0 folder
-/// is the canonical source for compiled template code, and templates for all TFMs currently
-/// resolve from the net11.0 folder on disk.
-///
-public class MinimalApiNet11IntegrationTests : IDisposable
+public class MinimalApiNet11IntegrationTests : MinimalApiIntegrationTestsBase
{
- private const string TargetFramework = "net11.0";
- private readonly string _testDirectory;
- private readonly string _testProjectDir;
- private readonly string _testProjectPath;
- private readonly Mock _mockFileSystem;
- private readonly TestTelemetryService _testTelemetryService;
- private readonly Mock _mockScaffolder;
- private readonly ScaffolderContext _context;
-
- public MinimalApiNet11IntegrationTests()
- {
- _testDirectory = Path.Combine(Path.GetTempPath(), "MinimalApiNet11IntegrationTests", Guid.NewGuid().ToString());
- _testProjectDir = Path.Combine(_testDirectory, "TestProject");
- _testProjectPath = Path.Combine(_testProjectDir, "TestProject.csproj");
- Directory.CreateDirectory(_testProjectDir);
-
- _mockFileSystem = new Mock();
- _testTelemetryService = new TestTelemetryService();
- _mockScaffolder = new Mock();
- _mockScaffolder.Setup(s => s.DisplayName).Returns(AspnetStrings.Api.MinimalApiDisplayName);
- _mockScaffolder.Setup(s => s.Name).Returns(AspnetStrings.Api.MinimalApi);
- _context = new ScaffolderContext(_mockScaffolder.Object);
- }
-
- public void Dispose()
- {
- if (Directory.Exists(_testDirectory))
- {
- try { Directory.Delete(_testDirectory, recursive: true); }
- catch { /* best-effort cleanup */ }
- }
- }
-
- #region Constants & Scaffolder Definition — Minimal API
-
- [Fact]
- public void ScaffolderName_IsMinimalApi_Net11()
- {
- Assert.Equal("minimalapi", AspnetStrings.Api.MinimalApi);
- }
-
- [Fact]
- public void ScaffolderDisplayName_IsMinimalApiDisplayName_Net11()
- {
- Assert.Equal("Minimal API", AspnetStrings.Api.MinimalApiDisplayName);
- }
-
- [Fact]
- public void ScaffolderDescription_IsMinimalApiDescription_Net11()
- {
- Assert.Equal("Generates an endpoints file (with CRUD API endpoints) given a model and optional DbContext.", AspnetStrings.Api.MinimalApiDescription);
- }
-
- [Fact]
- public void ScaffolderCategory_IsAPI_Net11()
- {
- Assert.Equal("API", AspnetStrings.Catagories.API);
- }
-
- [Fact]
- public void ScaffolderExample1_ContainsMinimalApiCommand_Net11()
- {
- Assert.Contains("minimalapi", AspnetStrings.Api.MinimalApiExample1);
- }
-
- [Fact]
- public void ScaffolderExample1_ContainsRequiredOptions_Net11()
- {
- Assert.Contains("--project", AspnetStrings.Api.MinimalApiExample1);
- Assert.Contains("--model", AspnetStrings.Api.MinimalApiExample1);
- Assert.Contains("--endpoints-class", AspnetStrings.Api.MinimalApiExample1);
- Assert.Contains("--data-context", AspnetStrings.Api.MinimalApiExample1);
- Assert.Contains("--database-provider", AspnetStrings.Api.MinimalApiExample1);
- }
-
- [Fact]
- public void ScaffolderExample1_ContainsOpenApiOption_Net11()
- {
- Assert.Contains("--openapi", AspnetStrings.Api.MinimalApiExample1);
- }
-
- [Fact]
- public void ScaffolderExample2_ContainsMinimalApiCommand_Net11()
- {
- Assert.Contains("minimalapi", AspnetStrings.Api.MinimalApiExample2);
- }
-
- [Fact]
- public void ScaffolderExample2_ContainsTypedResultsOption_Net11()
- {
- Assert.Contains("--typed-results", AspnetStrings.Api.MinimalApiExample2);
- }
-
- [Fact]
- public void ScaffolderExample2_ContainsOpenApiOption_Net11()
- {
- Assert.Contains("--openapi", AspnetStrings.Api.MinimalApiExample2);
- }
-
- [Fact]
- public void ScaffolderExample1Description_MentionsOpenAPI_Net11()
- {
- Assert.Contains("OpenAPI", AspnetStrings.Api.MinimalApiExample1Description);
- }
-
- [Fact]
- public void ScaffolderExample2Description_MentionsTypedResults_Net11()
- {
- Assert.Contains("TypedResults", AspnetStrings.Api.MinimalApiExample2Description);
- }
-
- [Fact]
- public void ScaffolderDescription_MentionsEndpointsFile_Net11()
- {
- Assert.Contains("endpoints file", AspnetStrings.Api.MinimalApiDescription);
- }
-
- [Fact]
- public void ScaffolderDescription_MentionsCRUD_Net11()
- {
- Assert.Contains("CRUD", AspnetStrings.Api.MinimalApiDescription);
- }
-
- [Fact]
- public void ScaffolderDescription_MentionsOptionalDbContext_Net11()
- {
- Assert.Contains("optional DbContext", AspnetStrings.Api.MinimalApiDescription);
- }
-
- #endregion
-
- #region CLI Options — Minimal API Specific
-
- [Fact]
- public void CliOption_ProjectOption_IsCorrect_Net11()
- {
- Assert.Equal("--project", AspNetConstants.CliOptions.ProjectCliOption);
- }
-
- [Fact]
- public void CliOption_ModelOption_IsCorrect_Net11()
- {
- Assert.Equal("--model", AspNetConstants.CliOptions.ModelCliOption);
- }
-
- [Fact]
- public void CliOption_DataContextOption_IsCorrect_Net11()
- {
- Assert.Equal("--dataContext", AspNetConstants.CliOptions.DataContextOption);
- }
-
- [Fact]
- public void CliOption_DbProviderOption_IsCorrect_Net11()
- {
- Assert.Equal("--dbProvider", AspNetConstants.CliOptions.DbProviderOption);
- }
-
- [Fact]
- public void CliOption_OpenApiOption_IsCorrect_Net11()
- {
- Assert.Equal("--open", AspNetConstants.CliOptions.OpenApiOption);
- }
-
- [Fact]
- public void CliOption_EndpointsOption_IsCorrect_Net11()
- {
- Assert.Equal("--endpoints", AspNetConstants.CliOptions.EndpointsOption);
- }
-
- [Fact]
- public void CliOption_TypedResultsOption_IsCorrect_Net11()
- {
- Assert.Equal("--typedResults", AspNetConstants.CliOptions.TypedResultsOption);
- }
-
- [Fact]
- public void CliOption_PrereleaseOption_IsCorrect_Net11()
- {
- Assert.Equal("--prerelease", AspNetConstants.CliOptions.PrereleaseCliOption);
- }
-
- #endregion
-
- #region AspNetOptions for MinimalApi
-
- [Fact]
- public void AspNetOptions_HasModelNameProperty_Net11()
- {
- var prop = typeof(AspNetOptions).GetProperty("ModelName");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasEndpointsClassProperty_Net11()
- {
- var prop = typeof(AspNetOptions).GetProperty("EndpointsClass");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasOpenApiProperty_Net11()
- {
- var prop = typeof(AspNetOptions).GetProperty("OpenApi");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasTypedResultsProperty_Net11()
- {
- var prop = typeof(AspNetOptions).GetProperty("TypedResults");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasDataContextClassProperty_Net11()
- {
- var prop = typeof(AspNetOptions).GetProperty("DataContextClass");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasDatabaseProviderProperty_Net11()
- {
- var prop = typeof(AspNetOptions).GetProperty("DatabaseProvider");
- Assert.NotNull(prop);
- }
-
- [Fact]
- public void AspNetOptions_HasPrereleaseProperty_Net11()
- {
- var prop = typeof(AspNetOptions).GetProperty("Prerelease");
- Assert.NotNull(prop);
- }
-
- #endregion
-
- #region ValidateMinimalApiStep — Properties and Construction
-
- [Fact]
- public void ValidateMinimalApiStep_IsScaffoldStep_Net11()
- {
- Assert.True(typeof(ValidateMinimalApiStep).IsAssignableTo(typeof(ScaffoldStep)));
- }
-
- [Fact]
- public void ValidateMinimalApiStep_HasProjectProperty_Net11()
- {
- Assert.NotNull(typeof(ValidateMinimalApiStep).GetProperty("Project"));
- }
-
- [Fact]
- public void ValidateMinimalApiStep_HasPrereleaseProperty_Net11()
- {
- Assert.NotNull(typeof(ValidateMinimalApiStep).GetProperty("Prerelease"));
- }
-
- [Fact]
- public void ValidateMinimalApiStep_HasEndpointsProperty_Net11()
- {
- Assert.NotNull(typeof(ValidateMinimalApiStep).GetProperty("Endpoints"));
- }
-
- [Fact]
- public void ValidateMinimalApiStep_HasOpenApiProperty_Net11()
- {
- Assert.NotNull(typeof(ValidateMinimalApiStep).GetProperty("OpenApi"));
- }
-
- [Fact]
- public void ValidateMinimalApiStep_HasTypedResultsProperty_Net11()
- {
- Assert.NotNull(typeof(ValidateMinimalApiStep).GetProperty("TypedResults"));
- }
-
- [Fact]
- public void ValidateMinimalApiStep_HasDatabaseProviderProperty_Net11()
- {
- Assert.NotNull(typeof(ValidateMinimalApiStep).GetProperty("DatabaseProvider"));
- }
-
- [Fact]
- public void ValidateMinimalApiStep_HasDataContextProperty_Net11()
- {
- Assert.NotNull(typeof(ValidateMinimalApiStep).GetProperty("DataContext"));
- }
-
- [Fact]
- public void ValidateMinimalApiStep_HasModelProperty_Net11()
- {
- Assert.NotNull(typeof(ValidateMinimalApiStep).GetProperty("Model"));
- }
-
- [Fact]
- public void ValidateMinimalApiStep_CanBeConstructed_Net11()
- {
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService);
-
- Assert.NotNull(step);
- }
-
- [Fact]
- public void ValidateMinimalApiStep_OpenApi_DefaultsToTrue_Net11()
- {
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService);
-
- Assert.True(step.OpenApi);
- }
-
- [Fact]
- public void ValidateMinimalApiStep_TypedResults_DefaultsToTrue_Net11()
- {
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService);
-
- Assert.True(step.TypedResults);
- }
-
- [Fact]
- public void ValidateMinimalApiStep_RequiresIFileSystem_Net11()
- {
- var ctor = typeof(ValidateMinimalApiStep).GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
- Assert.Single(ctor);
- var parameters = ctor[0].GetParameters();
- Assert.Contains(parameters, p => p.ParameterType == typeof(IFileSystem));
- }
-
- [Fact]
- public void ValidateMinimalApiStep_RequiresILogger_Net11()
- {
- var ctor = typeof(ValidateMinimalApiStep).GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
- Assert.Single(ctor);
- var parameters = ctor[0].GetParameters();
- Assert.Contains(parameters, p => p.ParameterType == typeof(ILogger));
- }
-
- [Fact]
- public void ValidateMinimalApiStep_RequiresITelemetryService_Net11()
- {
- var ctor = typeof(ValidateMinimalApiStep).GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
- Assert.Single(ctor);
- var parameters = ctor[0].GetParameters();
- Assert.Contains(parameters, p => p.ParameterType == typeof(ITelemetryService));
- }
-
- #endregion
-
- #region ValidateMinimalApiStep — Validation Logic
-
- [Fact]
- public async Task ValidateMinimalApiStep_FailsWhenProjectMissing_Net11()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- Endpoints = "ProductEndpoints",
- OpenApi = true,
- TypedResults = true,
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateMinimalApiStep_FailsWhenProjectFileDoesNotExist_Net11()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(false);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- Endpoints = "ProductEndpoints",
- OpenApi = true,
- TypedResults = true,
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateMinimalApiStep_FailsWhenModelMissing_Net11()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = string.Empty,
- Endpoints = "ProductEndpoints",
- OpenApi = true,
- TypedResults = true,
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- Assert.Single(_testTelemetryService.TrackedEvents);
- }
-
- [Fact]
- public async Task ValidateMinimalApiStep_StepProperties_AreSetCorrectly_Net11()
- {
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = "Product",
- Endpoints = "ProductEndpoints",
- OpenApi = true,
- TypedResults = false,
- DataContext = "AppDbContext",
- DatabaseProvider = PackageConstants.EfConstants.SqlServer,
- Prerelease = true
- };
-
- Assert.Equal(_testProjectPath, step.Project);
- Assert.Equal("Product", step.Model);
- Assert.Equal("ProductEndpoints", step.Endpoints);
- Assert.True(step.OpenApi);
- Assert.False(step.TypedResults);
- Assert.Equal("AppDbContext", step.DataContext);
- Assert.Equal(PackageConstants.EfConstants.SqlServer, step.DatabaseProvider);
- Assert.True(step.Prerelease);
- }
-
- [Fact]
- public async Task ValidateMinimalApiStep_FailsWhenProjectNull_Net11()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = null,
- Model = "Product",
- Endpoints = "ProductEndpoints",
- DataContext = "AppDbContext"
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- [Fact]
- public async Task ValidateMinimalApiStep_FailsWhenModelNull_Net11()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(_testProjectPath)).Returns(true);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = _testProjectPath,
- Model = null,
- Endpoints = "ProductEndpoints",
- DataContext = "AppDbContext"
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- [Fact]
- public async Task ValidateMinimalApiStep_AllFieldsEmpty_FailsValidation_Net11()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = string.Empty,
- Model = string.Empty,
- Endpoints = string.Empty,
- DataContext = string.Empty
- };
-
- bool result = await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.False(result);
- }
-
- #endregion
-
- #region Telemetry
-
- [Fact]
- public async Task TelemetryEventName_IsValidateMinimalApiStepEvent_Net11()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock>().Object,
- _testTelemetryService)
- {
- Project = string.Empty,
- Model = "Product",
- Endpoints = "ProductEndpoints"
- };
-
- await step.ExecuteAsync(_context, CancellationToken.None);
-
- Assert.Single(_testTelemetryService.TrackedEvents);
- Assert.Equal("ValidateMinimalApiStepEvent", _testTelemetryService.TrackedEvents[0].EventName);
- }
-
- [Fact]
- public async Task TelemetryResult_IsFailure_WhenValidationFails_Net11()
- {
- _mockFileSystem.Setup(fs => fs.FileExists(It.IsAny())).Returns(false);
-
- var step = new ValidateMinimalApiStep(
- _mockFileSystem.Object,
- new Mock