Skip to content

Commit

Permalink
Add UT for cross-assembly validation
Browse files Browse the repository at this point in the history
  • Loading branch information
zsolt-kolbay-sonarsource committed May 2, 2024
1 parent 2521c30 commit 41250d4
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ private static void ProcessControllerMethods(SonarSyntaxNodeReportingContext con
{
var modelParameterTypes = method.Parameters
.Where(x => !HasValidateNeverAttribute(x))
.SelectMany(x => RelatedTypesToExamine(x.Type))
.SelectMany(x => RelatedTypesToExamine(x.Type, method.ContainingType))
.Distinct();
foreach (var modelParameterType in modelParameterTypes)
{
Expand Down Expand Up @@ -132,13 +132,14 @@ private static void GetAllDeclaredProperties(ITypeSymbol type, ConcurrentDiction
}
}

private static IEnumerable<INamedTypeSymbol> RelatedTypesToExamine(ITypeSymbol type) =>
// We only consider Model types that are in the same assembly as the Controller, because Roslyn can't raise an issue when the location is in a different assembly than the one being analyzed.
private static IEnumerable<INamedTypeSymbol> RelatedTypesToExamine(ITypeSymbol type, ITypeSymbol controllerType) =>
type switch
{
IArrayTypeSymbol array => RelatedTypesToExamine(array.ElementType),
IArrayTypeSymbol array => RelatedTypesToExamine(array.ElementType, controllerType),
INamedTypeSymbol collection when collection.DerivesOrImplements(KnownType.System_Collections_Generic_IEnumerable_T) =>
collection.TypeArguments.SelectMany(RelatedTypesToExamine),
INamedTypeSymbol namedType => [namedType],
collection.TypeArguments.SelectMany(x => RelatedTypesToExamine(x, controllerType)),
INamedTypeSymbol namedType when type.IsInSameAssembly(controllerType) => [namedType],
_ => []
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,15 @@ namespace SonarAnalyzer.Test.Rules;
[TestClass]
public class AvoidUnderPostingTest
{
private readonly VerifierBuilder builder = new VerifierBuilder<AvoidUnderPosting>()
.WithBasePath("AspNet")
.AddReferences([
private static readonly IEnumerable<MetadataReference> AspNetReferences = [
AspNetCoreMetadataReference.MicrosoftAspNetCoreMvcAbstractions,
AspNetCoreMetadataReference.MicrosoftAspNetCoreMvcCore,
AspNetCoreMetadataReference.MicrosoftAspNetCoreMvcViewFeatures,
..NuGetMetadataReference.SystemComponentModelAnnotations(Constants.NuGetLatestVersion)
]);
..NuGetMetadataReference.SystemComponentModelAnnotations(Constants.NuGetLatestVersion)];

private readonly VerifierBuilder builder = new VerifierBuilder<AvoidUnderPosting>()
.WithBasePath("AspNet")
.AddReferences(AspNetReferences);

[TestMethod]
public void AvoidUnderPosting_CSharp() =>
Expand Down Expand Up @@ -103,6 +104,43 @@ public class ControllerClass : Controller
[{{attribute}}] public IActionResult Create(Model model) => View(model);
}
""").Verify();

[TestMethod]
public void AvoidUnderPosting_ModelInDifferentProject_CSharp()
{
const string modelCode = """
namespace Models
{
public class Person
{
public int Age { get; set; } // FN - Roslyn can't raise an issue when the location is in different project than the one being analyzed
}
}
""";
const string controllerCode = """
using Microsoft.AspNetCore.Mvc;
using Models;

namespace Controllers
{
public class PersonController : Controller
{
[HttpPost] public IActionResult Post(Person person) => View(person);
}
}
""";
var solution = SolutionBuilder.Create()
.AddProject(AnalyzerLanguage.CSharp)
.AddSnippet(modelCode)
.Solution
.AddProject(AnalyzerLanguage.CSharp)
.AddProjectReference(x => x.ProjectIds[0])
.AddReferences(AspNetReferences)
.AddSnippet(controllerCode)
.Solution;
var compiledAspNetProject = solution.Compile()[1];
DiagnosticVerifier.Verify(compiledAspNetProject, new AvoidUnderPosting());
}
}

#endif

0 comments on commit 41250d4

Please sign in to comment.