304 lines
8.3 KiB
C#
304 lines
8.3 KiB
C#
// Copyright (c) .NET Foundation. All rights reserved.
|
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
|
using System.Threading.Tasks;
|
|
using Microsoft.AspNetCore.Analyzer.Testing;
|
|
using Microsoft.AspNetCore.Mvc.Analyzers.Infrastructure;
|
|
using Microsoft.CodeAnalysis;
|
|
using Microsoft.CodeAnalysis.CodeFixes;
|
|
using Microsoft.CodeAnalysis.Diagnostics;
|
|
using Xunit;
|
|
|
|
namespace Microsoft.AspNetCore.Mvc.Analyzers
|
|
{
|
|
public class ApiActionsAreAttributeRoutedFacts : AnalyzerTestBase
|
|
{
|
|
private static DiagnosticDescriptor DiagnosticDescriptor = ExperimentalDiagnosticDescriptors.MVC7000_ApiActionsMustBeAttributeRouted;
|
|
|
|
protected override DiagnosticAnalyzer DiagnosticAnalyzer { get; }
|
|
= new ApiActionsAreAttributeRoutedAnalyzer();
|
|
|
|
protected override CodeFixProvider CodeFixProvider { get; }
|
|
= new ApiActionsAreAttributeRoutedFixProvider();
|
|
|
|
[Fact]
|
|
public async Task NoDiagnosticsAreReturned_FoEmptyScenarios()
|
|
{
|
|
// Arrange
|
|
var test = @"";
|
|
var project = CreateProject(test);
|
|
|
|
// Act
|
|
var result = await GetDiagnosticAsync(project);
|
|
|
|
// Assert
|
|
Assert.Empty(result);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task NoDiagnosticsAreReturned_WhenTypeIsNotApiController()
|
|
{
|
|
// Arrange
|
|
var test =
|
|
@"
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
public class HomeController : Controller
|
|
{
|
|
public IActionResult Index() => View();
|
|
}";
|
|
var project = CreateProject(test);
|
|
|
|
// Act
|
|
var result = await GetDiagnosticAsync(project);
|
|
|
|
// Assert
|
|
Assert.Empty(result);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task NoDiagnosticsAreReturned_WhenApiControllerActionHasAttribute()
|
|
{
|
|
// Arrange
|
|
var test =
|
|
@"
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
[ApiController]
|
|
public class PetController : Controller
|
|
{
|
|
[HttpGet]
|
|
public int GetPetId() => 0;
|
|
}";
|
|
var project = CreateProject(test);
|
|
|
|
// Act
|
|
var result = await GetDiagnosticAsync(project);
|
|
|
|
// Assert
|
|
Assert.Empty(result);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task NoDiagnosticsAreReturned_ForConstructors()
|
|
{
|
|
// Arrange
|
|
var test =
|
|
@"
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
[ApiController]
|
|
public class PetController : Controller
|
|
{
|
|
public PetController(){ }
|
|
}";
|
|
var project = CreateProject(test);
|
|
|
|
// Act
|
|
var result = await GetDiagnosticAsync(project);
|
|
|
|
// Assert
|
|
Assert.Empty(result);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task NoDiagnosticsAreReturned_ForNonActions()
|
|
{
|
|
// Arrange
|
|
var test =
|
|
@"
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
[ApiController]
|
|
public class PetController : Controller
|
|
{
|
|
private int GetPetIdPrivate() => 0;
|
|
protected int GetPetIdProtected() => 0;
|
|
public static IActionResult FindPetByStatus(int status) => null;
|
|
[NonAction]
|
|
public object Reset(int state) => null;
|
|
}";
|
|
var project = CreateProject(test);
|
|
|
|
// Act
|
|
var result = await GetDiagnosticAsync(project);
|
|
|
|
// Assert
|
|
Assert.Empty(result);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task DiagnosticsAndCodeFixes_WhenApiControllerActionDoesNotHaveAttribute()
|
|
{
|
|
// Arrange
|
|
var expectedLocation = new DiagnosticLocation("Test.cs", 8, 16);
|
|
var test =
|
|
@"
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
[ApiController]
|
|
[Route]
|
|
public class PetController : Controller
|
|
{
|
|
public int GetPetId() => 0;
|
|
}";
|
|
var expectedFix =
|
|
@"
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
[ApiController]
|
|
[Route]
|
|
public class PetController : Controller
|
|
{
|
|
[HttpGet]
|
|
public int GetPetId() => 0;
|
|
}";
|
|
var project = CreateProject(test);
|
|
|
|
// Act & Assert
|
|
var actualDiagnostics = await GetDiagnosticAsync(project);
|
|
AssertDiagnostic(expectedLocation, actualDiagnostics);
|
|
var actualFix = await ApplyCodeFixAsync(project, actualDiagnostics);
|
|
Assert.Equal(expectedFix, actualFix, ignoreLineEndingDifferences: true);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CodeFixes_ApplyFullyQualifiedNames()
|
|
{
|
|
// Arrange
|
|
var test =
|
|
@"
|
|
[Microsoft.AspNetCore.Mvc.ApiController]
|
|
[Microsoft.AspNetCore.Mvc.Route]
|
|
public class PetController
|
|
{
|
|
public object GetPet() => null;
|
|
}";
|
|
var expectedFix =
|
|
@"
|
|
[Microsoft.AspNetCore.Mvc.ApiController]
|
|
[Microsoft.AspNetCore.Mvc.Route]
|
|
public class PetController
|
|
{
|
|
[Microsoft.AspNetCore.Mvc.HttpGet]
|
|
public object GetPet() => null;
|
|
}";
|
|
var project = CreateProject(test);
|
|
|
|
// Act & Assert
|
|
var actualDiagnostics = await GetDiagnosticAsync(project);
|
|
var actualFix = await ApplyCodeFixAsync(project, actualDiagnostics);
|
|
Assert.Equal(expectedFix, actualFix, ignoreLineEndingDifferences: true);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("id")]
|
|
[InlineData("petId")]
|
|
public async Task CodeFixes_WithIdParameter(string idParameter)
|
|
{
|
|
// Arrange
|
|
var test =
|
|
$@"
|
|
using Microsoft.AspNetCore.Mvc;
|
|
[ApiController]
|
|
[Route]
|
|
public class PetController
|
|
{{
|
|
public IActionResult Post(string notid, int {idParameter}) => null;
|
|
}}";
|
|
var expectedFix =
|
|
$@"
|
|
using Microsoft.AspNetCore.Mvc;
|
|
[ApiController]
|
|
[Route]
|
|
public class PetController
|
|
{{
|
|
[HttpPost(""{{{idParameter}}}"")]
|
|
public IActionResult Post(string notid, int {idParameter}) => null;
|
|
}}";
|
|
var project = CreateProject(test);
|
|
|
|
// Act & Assert
|
|
var actualDiagnostics = await GetDiagnosticAsync(project);
|
|
var actualFix = await ApplyCodeFixAsync(project, actualDiagnostics);
|
|
Assert.Equal(expectedFix, actualFix, ignoreLineEndingDifferences: true);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CodeFixes_WithRouteParameter()
|
|
{
|
|
// Arrange
|
|
var test =
|
|
@"
|
|
using Microsoft.AspNetCore.Mvc;
|
|
[ApiController]
|
|
[Route]
|
|
public class PetController
|
|
{
|
|
public IActionResult DeletePetByStatus([FromRoute] Status status, [FromRoute] Category category) => null;
|
|
}";
|
|
var expectedFix =
|
|
@"
|
|
using Microsoft.AspNetCore.Mvc;
|
|
[ApiController]
|
|
[Route]
|
|
public class PetController
|
|
{
|
|
[HttpDelete(""{status}/{category}"")]
|
|
public IActionResult DeletePetByStatus([FromRoute] Status status, [FromRoute] Category category) => null;
|
|
}";
|
|
var project = CreateProject(test);
|
|
|
|
// Act & Assert
|
|
var actualDiagnostics = await GetDiagnosticAsync(project);
|
|
var actualFix = await ApplyCodeFixAsync(project, actualDiagnostics);
|
|
Assert.Equal(expectedFix, actualFix, ignoreLineEndingDifferences: true);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CodeFixes_WhenAttributeCannotBeInferred()
|
|
{
|
|
// Arrange
|
|
var test =
|
|
@"
|
|
using Microsoft.AspNetCore.Mvc;
|
|
[ApiController]
|
|
[Route]
|
|
public class PetController
|
|
{
|
|
public IActionResult ModifyPet() => null;
|
|
}";
|
|
var expectedFix =
|
|
@"
|
|
using Microsoft.AspNetCore.Mvc;
|
|
[ApiController]
|
|
[Route]
|
|
public class PetController
|
|
{
|
|
[HttpPut]
|
|
public IActionResult ModifyPet() => null;
|
|
}";
|
|
var project = CreateProject(test);
|
|
|
|
// Act & Assert
|
|
var actualDiagnostics = await GetDiagnosticAsync(project);
|
|
// There isn't a good way to test all fixes simultaneously. We'll pick the last one to verify when we
|
|
// expect to have 4 fixes.
|
|
var actualFix = await ApplyCodeFixAsync(project, actualDiagnostics, codeFixIndex: 3);
|
|
Assert.Equal(expectedFix, actualFix, ignoreLineEndingDifferences: true);
|
|
}
|
|
|
|
private void AssertDiagnostic(DiagnosticLocation expectedLocation, Diagnostic[] actualDiagnostics)
|
|
{
|
|
// Assert
|
|
Assert.Collection(
|
|
actualDiagnostics,
|
|
diagnostic =>
|
|
{
|
|
Assert.Equal(DiagnosticDescriptor.Id, diagnostic.Id);
|
|
Assert.Same(DiagnosticDescriptor, diagnostic.Descriptor);
|
|
AnalyzerAssert.DiagnosticLocation(expectedLocation, diagnostic.Location);
|
|
});
|
|
}
|
|
}
|
|
} |