Skip to content

Commit

Permalink
Add test cases with the latest version of EntityFrameworkCore
Browse files Browse the repository at this point in the history
  • Loading branch information
costin-zaharia-sonarsource committed Jan 21, 2022
1 parent 6377757 commit 4db4a9a
Show file tree
Hide file tree
Showing 8 changed files with 250 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ public abstract class ExecutingSqlQueriesBase<TSyntaxKind, TExpressionSyntax, TI
new(KnownType.Microsoft_EntityFrameworkCore_RelationalQueryableExtensions, "FromSql")
};

private readonly MemberDescriptor[] invocationsForFirstTwoArgumentsAfterV2 =
{
new(KnownType.Microsoft_EntityFrameworkCore_RelationalDatabaseFacadeExtensions, "ExecuteSqlRaw"),
new(KnownType.Microsoft_EntityFrameworkCore_RelationalDatabaseFacadeExtensions, "ExecuteSqlRawAsync"),
new(KnownType.Microsoft_EntityFrameworkCore_RelationalQueryableExtensions, "FromSqlRaw")
};

private readonly MemberDescriptor[] invocationsForFirstArgument =
{
new(KnownType.System_Data_Sqlite_SqliteCommand, "Execute")
Expand Down Expand Up @@ -116,6 +123,11 @@ protected override void Initialize(TrackerInput input)
inv.And(MethodHasRawSqlQueryParameter(), inv.Or(ArgumentAtIndexIsTracked(0), ArgumentAtIndexIsTracked(1))),
inv.ExceptWhen(inv.ArgumentAtIndexIsConstant(0)));

inv.Track(input,
inv.MatchMethod(invocationsForFirstTwoArgumentsAfterV2),
inv.Or(ArgumentAtIndexIsTracked(0), ArgumentAtIndexIsTracked(1)),
inv.ExceptWhen(inv.ArgumentAtIndexIsConstant(0)));

TrackInvocations(input, invocationsForFirstArgument, FirstArgumentIndex);
TrackInvocations(input, invocationsForSecondArgument, SecondArgumentIndex);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ namespace SonarAnalyzer.Helpers.Trackers
public class VisualBasicInvocationTracker : InvocationTracker<SyntaxKind>
{
protected override ILanguageFacade<SyntaxKind> Language => VisualBasicFacade.Instance;
protected override SyntaxKind[] TrackedSyntaxKinds { get; } = new[] { SyntaxKind.InvocationExpression };
protected override SyntaxKind[] TrackedSyntaxKinds { get; } = { SyntaxKind.InvocationExpression };

public override Condition ArgumentAtIndexIsConstant(int index) =>
context => ((InvocationExpressionSyntax)context.Node).ArgumentList is { } argumentList
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ private static string GetTestCaseFileName(string analyzerName) =>
"UsingCookies" => "UsingCookies_Net46",
"LooseFilePermissions" => "LooseFilePermissions.Windows",
#else
"ExecutingSqlQueries" => "ExecutingSqlQueries_NetCore",
"ExecutingSqlQueries" => "ExecutingSqlQueries_EntityFrameworkCoreLatest",
"UsingCookies" => "UsingCookies_NetCore",
"LooseFilePermissions" => "LooseFilePermissions.Unix",
"PermissiveCors" => "PermissiveCors.Net",
Expand Down Expand Up @@ -120,7 +120,7 @@ private static IEnumerable<MetadataReference> GetAdditionalReferences(string ana
nameof(UsingRegularExpressions) => MetadataReferenceFacade.RegularExpressions,
#if NET
nameof(DisablingCsrfProtection) => DisablingCsrfProtectionTest.AdditionalReferences(),
nameof(ExecutingSqlQueries) => ExecutingSqlQueriesTest.GetReferencesNetCore(Constants.DotNetCore220Version),
nameof(ExecutingSqlQueries) => ExecutingSqlQueriesTest.GetReferencesEntityFrameworkNetCore(Constants.NuGetLatestVersion),
nameof(LooseFilePermissions) => NuGetMetadataReference.MonoPosixNetStandard(),
nameof(PermissiveCors) => PermissiveCorsTest.AdditionalReferences,
nameof(UsingCookies) => UsingCookies.GetAdditionalReferencesForNetCore(Constants.DotNetCore220Version),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,15 @@ public class ExecutingSqlQueriesTest

[TestMethod]
public void ExecutingSqlQueries_CS_Net46() =>
builderCs.AddPaths(@"Hotspots\ExecutingSqlQueries_Net46.cs")
builderCs
.AddPaths(@"Hotspots\ExecutingSqlQueries_Net46.cs")
.AddReferences(GetReferencesNet46(Constants.NuGetLatestVersion))
.Verify();

[TestMethod]
public void ExecutingSqlQueries_VB_Net46() =>
builderVb.AddPaths(@"Hotspots\ExecutingSqlQueries_Net46.vb")
builderVb
.AddPaths(@"Hotspots\ExecutingSqlQueries_Net46.vb")
.WithOptions(ParseOptionsHelper.FromVisualBasic15)
.AddReferences(GetReferencesNet46(Constants.NuGetLatestVersion))
.Verify();
Expand All @@ -63,35 +65,55 @@ internal static IEnumerable<MetadataReference> GetReferencesNet46(string sqlServ
#else

[TestMethod]
public void ExecutingSqlQueries_CS_NetCore() =>
builderCs.AddPaths(@"Hotspots\ExecutingSqlQueries_NetCore.cs")
public void ExecutingSqlQueries_CS_EntityFrameworkCore2() =>
builderCs
.AddPaths(@"Hotspots\ExecutingSqlQueries_EntityFrameworkCore2.cs")
.WithOptions(ParseOptionsHelper.FromCSharp8)
.AddReferences(GetReferencesNetCore(Constants.DotNetCore220Version))
.AddReferences(GetReferencesEntityFrameworkNetCore("2.2.6"))
.Verify();

[TestMethod]
public void ExecutingSqlQueries_CS_EntityFrameworkCoreLatest() =>
builderCs
.AddPaths(@"Hotspots\ExecutingSqlQueries_EntityFrameworkCoreLatest.cs")
.WithOptions(ParseOptionsHelper.FromCSharp8)
.AddReferences(GetReferencesEntityFrameworkNetCore(Constants.NuGetLatestVersion))
.Verify();

[TestMethod]
public void ExecutingSqlQueries_CSharp9() =>
builderCs.AddPaths(@"Hotspots\ExecutingSqlQueries.CSharp9.cs")
builderCs
.AddPaths(@"Hotspots\ExecutingSqlQueries.CSharp9.cs")
.WithTopLevelStatements()
.AddReferences(GetReferencesNetCore(Constants.DotNetCore220Version).Concat(NuGetMetadataReference.MicrosoftDataSqliteCore()))
.AddReferences(GetReferencesEntityFrameworkNetCore(Constants.DotNetCore220Version).Concat(NuGetMetadataReference.MicrosoftDataSqliteCore()))
.Verify();

[TestMethod]
public void ExecutingSqlQueries_CSharp10() =>
builderCs.AddPaths(@"Hotspots\ExecutingSqlQueries.CSharp10.cs")
builderCs
.AddPaths(@"Hotspots\ExecutingSqlQueries.CSharp10.cs")
.WithOptions(ParseOptionsHelper.FromCSharp10)
.WithTopLevelStatements()
.AddReferences(GetReferencesNetCore(Constants.DotNetCore220Version).Concat(NuGetMetadataReference.MicrosoftDataSqliteCore()))
.AddReferences(GetReferencesEntityFrameworkNetCore(Constants.DotNetCore220Version).Concat(NuGetMetadataReference.MicrosoftDataSqliteCore()))
.Verify();

[TestMethod]
public void ExecutingSqlQueries_VB_EntityFrameworkCore2() =>
builderVb
.AddPaths(@"Hotspots\ExecutingSqlQueries_EntityFrameworkCore2.vb")
.WithOptions(ParseOptionsHelper.FromVisualBasic15)
.AddReferences(GetReferencesEntityFrameworkNetCore(Constants.DotNetCore220Version))
.Verify();

[TestMethod]
public void ExecutingSqlQueries_VB_NetCore() =>
builderVb.AddPaths(@"Hotspots\ExecutingSqlQueries_NetCore.vb")
public void ExecutingSqlQueries_VB_EntityFrameworkCoreLatest() =>
builderVb
.AddPaths(@"Hotspots\ExecutingSqlQueries_EntityFrameworkCoreLatest.vb")
.WithOptions(ParseOptionsHelper.FromVisualBasic15)
.AddReferences(GetReferencesNetCore(Constants.DotNetCore220Version))
.AddReferences(GetReferencesEntityFrameworkNetCore(Constants.NuGetLatestVersion))
.Verify();

internal static IEnumerable<MetadataReference> GetReferencesNetCore(string entityFrameworkVersion) =>
internal static IEnumerable<MetadataReference> GetReferencesEntityFrameworkNetCore(string entityFrameworkVersion) =>
Enumerable.Empty<MetadataReference>()
.Concat(NuGetMetadataReference.MicrosoftEntityFrameworkCore(entityFrameworkVersion))
.Concat(NuGetMetadataReference.MicrosoftEntityFrameworkCoreRelational(entityFrameworkVersion));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
using System;
using Microsoft.EntityFrameworkCore;

namespace Tests.Diagnostics
{
class Program
{
private const string ConstQuery = "";

public void Foo(DbContext context, string query, int x, Guid guid, params object[] parameters)
{
context.Database.ExecuteSqlRaw($""); // Compliant
context.Database.ExecuteSqlRaw(""); // Compliant, constants are safe
context.Database.ExecuteSqlRaw(ConstQuery); // Compliant, constants are safe
context.Database.ExecuteSqlRaw("" + ""); // Compliant, constants are safe
context.Database.ExecuteSqlRaw(query); // Compliant, not concat or format
context.Database.ExecuteSqlRaw("" + query); // Noncompliant
context.Database.ExecuteSqlRaw($"", parameters); // Compliant
context.Database.ExecuteSqlRaw(query, parameters); // Compliant, not concat or format

context.Database.ExecuteSqlRaw("" + query, parameters); // Noncompliant
context.Database.ExecuteSqlRaw($"SELECT * FROM mytable WHERE mycol={query} AND mycol2={0}", parameters[0]); // Noncompliant
context.Database.ExecuteSqlRaw($"SELECT * FROM mytable WHERE mycol={query}{query}", x, guid); // Noncompliant
context.Database.ExecuteSqlRaw(@$"SELECT * FROM mytable WHERE mycol={query}{query}", x, guid); // Noncompliant
context.Database.ExecuteSqlRaw($@"SELECT * FROM mytable WHERE mycol={query}{query}", x, guid); // Noncompliant
context.Database.ExecuteSqlRaw($"SELECT * FROM mytable WHERE mycol={query}"); // Noncompliant

RelationalDatabaseFacadeExtensions.ExecuteSqlRaw(context.Database, query); // Compliant
RelationalDatabaseFacadeExtensions.ExecuteSqlRaw(context.Database, $"SELECT * FROM mytable WHERE mycol={query}{query}", x, guid); // Noncompliant

context.Database.ExecuteSqlRawAsync($""); // Compliant, constants are safe
context.Database.ExecuteSqlRawAsync(""); // Compliant, constants are safe
context.Database.ExecuteSqlRawAsync(ConstQuery); // Compliant, constants are safe
context.Database.ExecuteSqlRawAsync("" + ""); // Compliant, constants are safe
context.Database.ExecuteSqlRawAsync(query); // Compliant, not concat
context.Database.ExecuteSqlRawAsync("" + query); // Noncompliant
context.Database.ExecuteSqlRawAsync(query + ""); // Noncompliant
context.Database.ExecuteSqlRawAsync("" + query + ""); // Noncompliant
context.Database.ExecuteSqlRawAsync($"", parameters); // Compliant
context.Database.ExecuteSqlRawAsync(query, parameters); // Compliant, not concat or format

context.Database.ExecuteSqlRawAsync("" + query, parameters); // Noncompliant
RelationalDatabaseFacadeExtensions.ExecuteSqlRawAsync(context.Database, "" + query, parameters); // Noncompliant

context.Set<User>().FromSqlRaw($""); // Compliant
context.Set<User>().FromSqlRaw(""); // Compliant, constants are safe
context.Set<User>().FromSqlRaw(ConstQuery); // Compliant, constants are safe
context.Set<User>().FromSqlRaw(query); // Compliant, not concat/format
context.Set<User>().FromSqlRaw("" + ""); // Compliant
context.Set<User>().FromSqlRaw($"", parameters); // Compliant
context.Set<User>().FromSqlRaw("", parameters); // Compliant, the parameters are sanitized
context.Set<User>().FromSqlRaw(query, parameters); // Compliant
context.Set<User>().FromSqlRaw("" + query, parameters); // Noncompliant
RelationalQueryableExtensions.FromSqlRaw(context.Set<User>(), "" + query, parameters); // Noncompliant
}

public void ConcatAndFormat(DbContext context, string query, params object[] parameters)
{
var concatenated = string.Concat(query, parameters); // Secondary [1,2,3]
var formatted = string.Format("INSERT INTO Users (name) VALUES (\"{0}\")", parameters); // Secondary [4,5,6]
var interpolated = $"SELECT * FROM mytable WHERE mycol={parameters[0]}"; // Secondary [7,8,9]

context.Database.ExecuteSqlRaw(string.Concat(query, parameters)); // Noncompliant
context.Database.ExecuteSqlRaw(string.Format(query, parameters)); // Noncompliant
context.Database.ExecuteSqlRaw(string.Format("INSERT INTO Users (name) VALUES (\"{0}\")", parameters)); // Noncompliant
context.Database.ExecuteSqlRaw($"SELECT * FROM mytable WHERE mycol={parameters[0]}"); // Noncompliant
context.Database.ExecuteSqlRaw("SELECT * FROM mytable WHERE mycol=" + parameters[0]); // Noncompliant
context.Database.ExecuteSqlRaw(formatted); // Noncompliant [4]
context.Database.ExecuteSqlRaw(concatenated); // Noncompliant [1]
context.Database.ExecuteSqlRaw(interpolated); // Noncompliant [7]

context.Database.ExecuteSqlRawAsync(string.Concat(query, parameters)); // Noncompliant
context.Database.ExecuteSqlRawAsync(string.Format(query, parameters)); // Noncompliant
context.Database.ExecuteSqlRawAsync(string.Format("INSERT INTO Users (name) VALUES (\"{0}\")", parameters)); // Noncompliant
context.Database.ExecuteSqlRawAsync($"SELECT * FROM mytable WHERE mycol={parameters[0]}"); // Noncompliant
context.Database.ExecuteSqlRawAsync("SELECT * FROM mytable WHERE mycol=" + parameters[0]); // Noncompliant
context.Database.ExecuteSqlRawAsync(formatted); // Noncompliant [5]
context.Database.ExecuteSqlRawAsync(concatenated); // Noncompliant [2]
context.Database.ExecuteSqlRawAsync(interpolated); // Noncompliant [8]

context.Set<User>().FromSqlRaw(string.Concat(query, parameters)); // Noncompliant
context.Set<User>().FromSqlRaw(string.Format("INSERT INTO Users (name) VALUES (\"{0}\")", parameters)); // Noncompliant
context.Set<User>().FromSqlRaw($"SELECT * FROM mytable WHERE mycol={parameters[0]}"); // Noncompliant
context.Set<User>().FromSqlRaw("SELECT * FROM mytable WHERE mycol=" + parameters[0]); // Noncompliant
context.Set<User>().FromSqlRaw(formatted); // Noncompliant [6]
context.Set<User>().FromSqlRaw(concatenated); // Noncompliant [3]
context.Set<User>().FromSqlRaw(interpolated); // Noncompliant [9]
}
}

class User
{
string Id { get; set; }
string Name { get; set; }
}
}
Loading

0 comments on commit 4db4a9a

Please sign in to comment.