diff --git a/src/EFCore.Relational/Query/QuerySqlGenerator.cs b/src/EFCore.Relational/Query/QuerySqlGenerator.cs index d05ffa71cb3..f57e880b956 100644 --- a/src/EFCore.Relational/Query/QuerySqlGenerator.cs +++ b/src/EFCore.Relational/Query/QuerySqlGenerator.cs @@ -338,7 +338,7 @@ protected override Expression VisitTable(TableExpression tableExpression) private void GenerateFromSql(FromSqlExpression fromSqlExpression) { var sql = fromSqlExpression.Sql; - string[]? substitutions = null; + string[]? substitutions; switch (fromSqlExpression.Arguments) { @@ -430,7 +430,7 @@ protected virtual void CheckComposableSql(string sql) { var i = span.IndexOf('\n'); span = i > 0 - ? span.Slice(i + 1).TrimStart() + ? span[(i + 1)..].TrimStart() : throw new InvalidOperationException(RelationalStrings.FromSqlNonComposable); continue; } @@ -440,7 +440,7 @@ protected virtual void CheckComposableSql(string sql) { var i = span.IndexOf("*/"); span = i > 0 - ? span.Slice(i + 2).TrimStart() + ? span[(i + 2)..].TrimStart() : throw new InvalidOperationException(RelationalStrings.FromSqlNonComposable); continue; } @@ -459,18 +459,11 @@ protected virtual void CheckComposableSql(string sql) /// The given SQL isn't composable. protected virtual void CheckComposableSqlTrimmed(ReadOnlySpan sql) { - if (sql.StartsWith("SELECT", StringComparison.OrdinalIgnoreCase)) - { - sql = sql.Slice("SELECT".Length); - } - else if (sql.StartsWith("WITH", StringComparison.OrdinalIgnoreCase)) - { - sql = sql.Slice("WITH".Length); - } - else - { - throw new InvalidOperationException(RelationalStrings.FromSqlNonComposable); - } + sql = sql.StartsWith("SELECT", StringComparison.OrdinalIgnoreCase) + ? sql["SELECT".Length..] + : sql.StartsWith("WITH", StringComparison.OrdinalIgnoreCase) + ? sql["WITH".Length..] + : throw new InvalidOperationException(RelationalStrings.FromSqlNonComposable); if (sql.Length > 0 && (char.IsWhiteSpace(sql[0]) || sql.StartsWith("--") || sql.StartsWith("/*"))) @@ -484,7 +477,7 @@ protected virtual void CheckComposableSqlTrimmed(ReadOnlySpan sql) /// protected override Expression VisitSqlBinary(SqlBinaryExpression sqlBinaryExpression) { - var requiresBrackets = RequiresBrackets(sqlBinaryExpression.Left); + var requiresBrackets = RequiresParentheses(sqlBinaryExpression, sqlBinaryExpression.Left); if (requiresBrackets) { @@ -500,7 +493,7 @@ protected override Expression VisitSqlBinary(SqlBinaryExpression sqlBinaryExpres _relationalCommandBuilder.Append(GetOperator(sqlBinaryExpression)); - requiresBrackets = RequiresBrackets(sqlBinaryExpression.Right); + requiresBrackets = RequiresParentheses(sqlBinaryExpression, sqlBinaryExpression.Right); if (requiresBrackets) { @@ -517,14 +510,6 @@ protected override Expression VisitSqlBinary(SqlBinaryExpression sqlBinaryExpres return sqlBinaryExpression; } - private static bool RequiresBrackets(SqlExpression expression) - => expression is SqlBinaryExpression - || expression is LikeExpression - || (expression is SqlUnaryExpression unary - && unary.Operand.Type == typeof(bool) - && (unary.OperatorType == ExpressionType.Equal - || unary.OperatorType == ExpressionType.NotEqual)); - /// protected override Expression VisitSqlConstant(SqlConstantExpression sqlConstantExpression) { @@ -661,7 +646,7 @@ protected override Expression VisitSqlUnary(SqlUnaryExpression sqlUnaryExpressio case ExpressionType.Convert: { _relationalCommandBuilder.Append("CAST("); - var requiresBrackets = RequiresBrackets(sqlUnaryExpression.Operand); + var requiresBrackets = RequiresParentheses(sqlUnaryExpression, sqlUnaryExpression.Operand); if (requiresBrackets) { _relationalCommandBuilder.Append("("); @@ -712,7 +697,7 @@ protected override Expression VisitSqlUnary(SqlUnaryExpression sqlUnaryExpressio case ExpressionType.Negate: { _relationalCommandBuilder.Append("-"); - var requiresBrackets = RequiresBrackets(sqlUnaryExpression.Operand); + var requiresBrackets = RequiresParentheses(sqlUnaryExpression, sqlUnaryExpression.Operand); if (requiresBrackets) { _relationalCommandBuilder.Append("("); @@ -790,6 +775,56 @@ protected override Expression VisitIn(InExpression inExpression) protected virtual string GetOperator(SqlBinaryExpression binaryExpression) => _operatorMap[binaryExpression.OperatorType]; + /// + /// Returns a bool value indicating if the inner SQL expression required to be put inside parenthesis + /// when generating SQL for outer SQL expression. + /// + /// The outer expression which provides context in which SQL is being generated. + /// The inner expression which may need to be put inside parenthesis. + /// A bool value indicating that parenthesis is required or not. + protected virtual bool RequiresParentheses(SqlExpression outerExpression, SqlExpression innerExpression) + { + switch (innerExpression) + { + case LikeExpression _: + return true; + + case SqlUnaryExpression sqlUnaryExpression: + { + // Wrap IS (NOT) NULL operation when applied on bool column. + if ((sqlUnaryExpression.OperatorType == ExpressionType.Equal + || sqlUnaryExpression.OperatorType == ExpressionType.NotEqual) + && sqlUnaryExpression.Operand.Type == typeof(bool)) + { + return true; + } + + return false; + } + + case SqlBinaryExpression sqlBinaryExpression: + { + //if (outerExpression is SqlBinaryExpression outerBinary) + //{ + // if (outerBinary.OperatorType == ExpressionType.AndAlso) + // { + // return sqlBinaryExpression.OperatorType == ExpressionType.OrElse; + // } + + // if (outerBinary.OperatorType == ExpressionType.OrElse) + // { + // // Precedence-wise AND is above OR but we still add parenthesis for ease of understanding + // return sqlBinaryExpression.OperatorType == ExpressionType.AndAlso; + // } + //} + + return true; + } + } + + return false; + } + /// /// Generates a TOP construct in the relational command /// diff --git a/test/EFCore.SqlServer.FunctionalTests/LazyLoadProxySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/LazyLoadProxySqlServerTest.cs index 0d42f118b72..5cf3f4c6df7 100644 --- a/test/EFCore.SqlServer.FunctionalTests/LazyLoadProxySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/LazyLoadProxySqlServerTest.cs @@ -1,6 +1,8 @@ // 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.IO; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.TestUtilities; @@ -20,161 +22,141 @@ public override void Lazy_load_collection(EntityState state, bool useAttach, boo { base.Lazy_load_collection(state, useAttach, useDetach); - Assert.Equal( + AssertSql( @"@__p_0='707' (Nullable = true) SELECT [c].[Id], [c].[ParentId] FROM [Child] AS [c] -WHERE [c].[ParentId] = @__p_0", - Sql, - ignoreLineEndingDifferences: true); +WHERE [c].[ParentId] = @__p_0"); } public override void Lazy_load_many_to_one_reference_to_principal(EntityState state, bool useAttach, bool useDetach) { base.Lazy_load_many_to_one_reference_to_principal(state, useAttach, useDetach); - Assert.Equal( + AssertSql( @"@__p_0='707' SELECT [p].[Id], [p].[AlternateId], [p].[Discriminator] FROM [Parent] AS [p] -WHERE [p].[Id] = @__p_0", - Sql, - ignoreLineEndingDifferences: true); +WHERE [p].[Id] = @__p_0"); } public override void Lazy_load_one_to_one_reference_to_principal(EntityState state, bool useAttach, bool useDetach) { base.Lazy_load_one_to_one_reference_to_principal(state, useAttach, useDetach); - Assert.Equal( + AssertSql( @"@__p_0='707' SELECT [p].[Id], [p].[AlternateId], [p].[Discriminator] FROM [Parent] AS [p] -WHERE [p].[Id] = @__p_0", - Sql, - ignoreLineEndingDifferences: true); +WHERE [p].[Id] = @__p_0"); } public override void Lazy_load_one_to_one_reference_to_dependent(EntityState state, bool useAttach, bool useDetach) { base.Lazy_load_one_to_one_reference_to_dependent(state, useAttach, useDetach); - Assert.Equal( + AssertSql( @"@__p_0='707' (Nullable = true) SELECT [s].[Id], [s].[ParentId] FROM [Single] AS [s] -WHERE [s].[ParentId] = @__p_0", - Sql, - ignoreLineEndingDifferences: true); +WHERE [s].[ParentId] = @__p_0"); } public override void Lazy_load_one_to_one_PK_to_PK_reference_to_principal(EntityState state) { base.Lazy_load_one_to_one_PK_to_PK_reference_to_principal(state); - Assert.Equal( + AssertSql( @"@__p_0='707' SELECT [p].[Id], [p].[AlternateId], [p].[Discriminator] FROM [Parent] AS [p] -WHERE [p].[Id] = @__p_0", - Sql, - ignoreLineEndingDifferences: true); +WHERE [p].[Id] = @__p_0"); } public override void Lazy_load_one_to_one_PK_to_PK_reference_to_dependent(EntityState state) { base.Lazy_load_one_to_one_PK_to_PK_reference_to_dependent(state); - Assert.Equal( + AssertSql( @"@__p_0='707' SELECT [s].[Id] FROM [SinglePkToPk] AS [s] -WHERE [s].[Id] = @__p_0", - Sql, - ignoreLineEndingDifferences: true); +WHERE [s].[Id] = @__p_0"); } public override void Lazy_load_many_to_one_reference_to_principal_null_FK(EntityState state) { base.Lazy_load_many_to_one_reference_to_principal_null_FK(state); - Assert.Equal("", Sql); + AssertSql(@""); } public override void Lazy_load_one_to_one_reference_to_principal_null_FK(EntityState state) { base.Lazy_load_one_to_one_reference_to_principal_null_FK(state); - Assert.Equal("", Sql); + AssertSql(@""); } public override void Lazy_load_collection_not_found(EntityState state) { base.Lazy_load_collection_not_found(state); - Assert.Equal( + AssertSql( @"@__p_0='767' (Nullable = true) SELECT [c].[Id], [c].[ParentId] FROM [Child] AS [c] -WHERE [c].[ParentId] = @__p_0", - Sql, - ignoreLineEndingDifferences: true); +WHERE [c].[ParentId] = @__p_0"); } public override void Lazy_load_many_to_one_reference_to_principal_not_found(EntityState state) { base.Lazy_load_many_to_one_reference_to_principal_not_found(state); - Assert.Equal( + AssertSql( @"@__p_0='787' SELECT [p].[Id], [p].[AlternateId], [p].[Discriminator] FROM [Parent] AS [p] -WHERE [p].[Id] = @__p_0", - Sql, - ignoreLineEndingDifferences: true); +WHERE [p].[Id] = @__p_0"); } public override void Lazy_load_one_to_one_reference_to_principal_not_found(EntityState state) { base.Lazy_load_one_to_one_reference_to_principal_not_found(state); - Assert.Equal( + AssertSql( @"@__p_0='787' SELECT [p].[Id], [p].[AlternateId], [p].[Discriminator] FROM [Parent] AS [p] -WHERE [p].[Id] = @__p_0", - Sql, - ignoreLineEndingDifferences: true); +WHERE [p].[Id] = @__p_0"); } public override void Lazy_load_one_to_one_reference_to_dependent_not_found(EntityState state) { base.Lazy_load_one_to_one_reference_to_dependent_not_found(state); - Assert.Equal( + AssertSql( @"@__p_0='767' (Nullable = true) SELECT [s].[Id], [s].[ParentId] FROM [Single] AS [s] -WHERE [s].[ParentId] = @__p_0", - Sql, - ignoreLineEndingDifferences: true); +WHERE [s].[ParentId] = @__p_0"); } public override void Lazy_load_collection_already_loaded(EntityState state, CascadeTiming cascadeDeleteTiming) { base.Lazy_load_collection_already_loaded(state, cascadeDeleteTiming); - Assert.Equal("", Sql); + AssertSql(@""); } public override void Lazy_load_many_to_one_reference_to_principal_already_loaded( @@ -183,14 +165,14 @@ public override void Lazy_load_many_to_one_reference_to_principal_already_loaded { base.Lazy_load_many_to_one_reference_to_principal_already_loaded(state, cascadeDeleteTiming); - Assert.Equal("", Sql); + AssertSql(@""); } public override void Lazy_load_one_to_one_reference_to_principal_already_loaded(EntityState state) { base.Lazy_load_one_to_one_reference_to_principal_already_loaded(state); - Assert.Equal("", Sql); + AssertSql(@""); } public override void Lazy_load_one_to_one_reference_to_dependent_already_loaded( @@ -199,221 +181,199 @@ public override void Lazy_load_one_to_one_reference_to_dependent_already_loaded( { base.Lazy_load_one_to_one_reference_to_dependent_already_loaded(state, cascadeDeleteTiming); - Assert.Equal("", Sql); + AssertSql(@""); } public override void Lazy_load_one_to_one_PK_to_PK_reference_to_principal_already_loaded(EntityState state) { base.Lazy_load_one_to_one_PK_to_PK_reference_to_principal_already_loaded(state); - Assert.Equal("", Sql); + AssertSql(@""); } public override void Lazy_load_one_to_one_PK_to_PK_reference_to_dependent_already_loaded(EntityState state) { base.Lazy_load_one_to_one_PK_to_PK_reference_to_dependent_already_loaded(state); - Assert.Equal("", Sql); + AssertSql(@""); } public override void Lazy_load_many_to_one_reference_to_principal_alternate_key(EntityState state) { base.Lazy_load_many_to_one_reference_to_principal_alternate_key(state); - Assert.Equal( + AssertSql( @"@__p_0='Root' (Size = 450) SELECT [p].[Id], [p].[AlternateId], [p].[Discriminator] FROM [Parent] AS [p] -WHERE [p].[AlternateId] = @__p_0", - Sql, - ignoreLineEndingDifferences: true); +WHERE [p].[AlternateId] = @__p_0"); } public override void Lazy_load_one_to_one_reference_to_principal_alternate_key(EntityState state) { base.Lazy_load_one_to_one_reference_to_principal_alternate_key(state); - Assert.Equal( + AssertSql( @"@__p_0='Root' (Size = 450) SELECT [p].[Id], [p].[AlternateId], [p].[Discriminator] FROM [Parent] AS [p] -WHERE [p].[AlternateId] = @__p_0", - Sql, - ignoreLineEndingDifferences: true); +WHERE [p].[AlternateId] = @__p_0"); } public override void Lazy_load_one_to_one_reference_to_dependent_alternate_key(EntityState state) { base.Lazy_load_one_to_one_reference_to_dependent_alternate_key(state); - Assert.Equal( + AssertSql( @"@__p_0='Root' (Size = 450) SELECT [s].[Id], [s].[ParentId] FROM [SingleAk] AS [s] -WHERE [s].[ParentId] = @__p_0", - Sql, - ignoreLineEndingDifferences: true); +WHERE [s].[ParentId] = @__p_0"); } public override void Lazy_load_many_to_one_reference_to_principal_null_FK_alternate_key(EntityState state) { base.Lazy_load_many_to_one_reference_to_principal_null_FK_alternate_key(state); - Assert.Equal("", Sql); + AssertSql(@""); } public override void Lazy_load_one_to_one_reference_to_principal_null_FK_alternate_key(EntityState state) { base.Lazy_load_one_to_one_reference_to_principal_null_FK_alternate_key(state); - Assert.Equal("", Sql); + AssertSql(@""); } public override void Lazy_load_collection_shadow_fk(EntityState state) { base.Lazy_load_collection_shadow_fk(state); - Assert.Equal( + AssertSql( @"@__p_0='707' (Nullable = true) SELECT [c].[Id], [c].[ParentId] FROM [ChildShadowFk] AS [c] -WHERE [c].[ParentId] = @__p_0", - Sql, - ignoreLineEndingDifferences: true); +WHERE [c].[ParentId] = @__p_0"); } public override void Lazy_load_many_to_one_reference_to_principal_shadow_fk(EntityState state) { base.Lazy_load_many_to_one_reference_to_principal_shadow_fk(state); - Assert.Equal( + AssertSql( @"@__p_0='707' SELECT [p].[Id], [p].[AlternateId], [p].[Discriminator] FROM [Parent] AS [p] -WHERE [p].[Id] = @__p_0", - Sql, - ignoreLineEndingDifferences: true); +WHERE [p].[Id] = @__p_0"); } public override void Lazy_load_one_to_one_reference_to_principal_shadow_fk(EntityState state) { base.Lazy_load_one_to_one_reference_to_principal_shadow_fk(state); - Assert.Equal( + AssertSql( @"@__p_0='707' SELECT [p].[Id], [p].[AlternateId], [p].[Discriminator] FROM [Parent] AS [p] -WHERE [p].[Id] = @__p_0", - Sql, - ignoreLineEndingDifferences: true); +WHERE [p].[Id] = @__p_0"); } public override void Lazy_load_one_to_one_reference_to_dependent_shadow_fk(EntityState state) { base.Lazy_load_one_to_one_reference_to_dependent_shadow_fk(state); - Assert.Equal( + AssertSql( @"@__p_0='707' (Nullable = true) SELECT [s].[Id], [s].[ParentId] FROM [SingleShadowFk] AS [s] -WHERE [s].[ParentId] = @__p_0", - Sql, - ignoreLineEndingDifferences: true); +WHERE [s].[ParentId] = @__p_0"); } public override void Lazy_load_many_to_one_reference_to_principal_null_FK_shadow_fk(EntityState state) { base.Lazy_load_many_to_one_reference_to_principal_null_FK_shadow_fk(state); - Assert.Equal("", Sql); + AssertSql(@""); } public override void Lazy_load_one_to_one_reference_to_principal_null_FK_shadow_fk(EntityState state) { base.Lazy_load_one_to_one_reference_to_principal_null_FK_shadow_fk(state); - Assert.Equal("", Sql); + AssertSql(@""); } public override void Lazy_load_collection_composite_key(EntityState state) { base.Lazy_load_collection_composite_key(state); - Assert.Equal( + AssertSql( @"@__p_0='Root' (Size = 450) @__p_1='707' (Nullable = true) SELECT [c].[Id], [c].[ParentAlternateId], [c].[ParentId] FROM [ChildCompositeKey] AS [c] -WHERE ([c].[ParentAlternateId] = @__p_0) AND ([c].[ParentId] = @__p_1)", - Sql, - ignoreLineEndingDifferences: true); +WHERE ([c].[ParentAlternateId] = @__p_0) AND ([c].[ParentId] = @__p_1)"); } public override void Lazy_load_many_to_one_reference_to_principal_composite_key(EntityState state) { base.Lazy_load_many_to_one_reference_to_principal_composite_key(state); - Assert.Equal( + AssertSql( @"@__p_0='Root' (Size = 450) @__p_1='707' SELECT [p].[Id], [p].[AlternateId], [p].[Discriminator] FROM [Parent] AS [p] -WHERE ([p].[AlternateId] = @__p_0) AND ([p].[Id] = @__p_1)", - Sql, - ignoreLineEndingDifferences: true); +WHERE ([p].[AlternateId] = @__p_0) AND ([p].[Id] = @__p_1)"); } public override void Lazy_load_one_to_one_reference_to_principal_composite_key(EntityState state) { base.Lazy_load_one_to_one_reference_to_principal_composite_key(state); - Assert.Equal( + AssertSql( @"@__p_0='Root' (Size = 450) @__p_1='707' SELECT [p].[Id], [p].[AlternateId], [p].[Discriminator] FROM [Parent] AS [p] -WHERE ([p].[AlternateId] = @__p_0) AND ([p].[Id] = @__p_1)", - Sql, - ignoreLineEndingDifferences: true); +WHERE ([p].[AlternateId] = @__p_0) AND ([p].[Id] = @__p_1)"); } public override void Lazy_load_one_to_one_reference_to_dependent_composite_key(EntityState state) { base.Lazy_load_one_to_one_reference_to_dependent_composite_key(state); - Assert.Equal( + AssertSql( @"@__p_0='Root' (Size = 450) @__p_1='707' (Nullable = true) SELECT [s].[Id], [s].[ParentAlternateId], [s].[ParentId] FROM [SingleCompositeKey] AS [s] -WHERE ([s].[ParentAlternateId] = @__p_0) AND ([s].[ParentId] = @__p_1)", - Sql, - ignoreLineEndingDifferences: true); +WHERE ([s].[ParentAlternateId] = @__p_0) AND ([s].[ParentId] = @__p_1)"); } public override void Lazy_load_many_to_one_reference_to_principal_null_FK_composite_key(EntityState state) { base.Lazy_load_many_to_one_reference_to_principal_null_FK_composite_key(state); - Assert.Equal("", Sql); + AssertSql(@""); } public override void Lazy_load_one_to_one_reference_to_principal_null_FK_composite_key(EntityState state) { base.Lazy_load_one_to_one_reference_to_principal_null_FK_composite_key(state); - Assert.Equal("", Sql); + AssertSql(@""); } public override async Task Load_collection(EntityState state, bool async) @@ -422,14 +382,12 @@ public override async Task Load_collection(EntityState state, bool async) if (!async) { - Assert.Equal( + AssertSql( @"@__p_0='707' (Nullable = true) SELECT [c].[Id], [c].[ParentId] FROM [Child] AS [c] -WHERE [c].[ParentId] = @__p_0", - Sql, - ignoreLineEndingDifferences: true); +WHERE [c].[ParentId] = @__p_0"); } } @@ -438,7 +396,7 @@ public override void Top_level_projection_track_entities_before_passing_to_clien { base.Top_level_projection_track_entities_before_passing_to_client_method(); - Assert.Equal( + AssertSql( @"SELECT TOP(1) [p].[Id], [p].[AlternateId], [p].[Discriminator] FROM [Parent] AS [p] ORDER BY [p].[Id] @@ -447,24 +405,20 @@ ORDER BY [p].[Id] SELECT [s].[Id], [s].[ParentId] FROM [Single] AS [s] -WHERE [s].[ParentId] = @__p_0", - Sql, - ignoreLineEndingDifferences: true); +WHERE [s].[ParentId] = @__p_0"); } public override async Task Entity_equality_with_proxy_parameter(bool async) { await base.Entity_equality_with_proxy_parameter(async); - Assert.Equal( + AssertSql( @"@__entity_equality_called_0_Id='707' (Nullable = true) SELECT [c].[Id], [c].[ParentId] FROM [Child] AS [c] LEFT JOIN [Parent] AS [p] ON [c].[ParentId] = [p].[Id] -WHERE [p].[Id] = @__entity_equality_called_0_Id", - Sql, - ignoreLineEndingDifferences: true); +WHERE [p].[Id] = @__entity_equality_called_0_Id"); } protected override void ClearLog() @@ -473,6 +427,51 @@ protected override void ClearLog() protected override void RecordLog() => Sql = Fixture.TestSqlLoggerFactory.Sql; + private const string FileNewLine = @" +"; + + private void AssertSql(string expected) + { + try + { + Assert.Equal( + expected, Sql, ignoreLineEndingDifferences: true); + } + catch + { + var methodCallLine = Environment.StackTrace.Split( + new[] { Environment.NewLine }, + StringSplitOptions.RemoveEmptyEntries)[2][6..]; + + var indexMethodEnding = methodCallLine.IndexOf(')') + 1; + var testName = methodCallLine.Substring(0, indexMethodEnding); + var parts = methodCallLine[indexMethodEnding..].Split(" ", StringSplitOptions.RemoveEmptyEntries); + var fileName = parts[1][..^5]; + var lineNumber = int.Parse(parts[2]); + + var currentDirectory = Directory.GetCurrentDirectory(); + var logFile = currentDirectory.Substring( + 0, + currentDirectory.LastIndexOf( + $"{Path.DirectorySeparatorChar}artifacts{Path.DirectorySeparatorChar}", + StringComparison.Ordinal) + 1) + + "QueryBaseline.txt"; + + var testInfo = testName + " : " + lineNumber + FileNewLine; + var newBaseLine = $@" AssertSql( + {"@\"" + Sql.Replace("\"", "\"\"") + "\""}); + +"; + + var contents = testInfo + newBaseLine + FileNewLine + "--------------------" + FileNewLine; + + File.AppendAllText(logFile, contents); + + throw; + } + } + + private string Sql { get; set; } public class LoadSqlServerFixture : LoadFixtureBase diff --git a/test/EFCore.SqlServer.FunctionalTests/LoadSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/LoadSqlServerTest.cs index e0fc14186b8..8ceb2fd8495 100644 --- a/test/EFCore.SqlServer.FunctionalTests/LoadSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/LoadSqlServerTest.cs @@ -1463,9 +1463,7 @@ private void AssertSql(string expected) try { Assert.Equal( - expected, - Sql, - ignoreLineEndingDifferences: true); + expected, Sql, ignoreLineEndingDifferences: true); } catch { @@ -1473,24 +1471,27 @@ private void AssertSql(string expected) new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)[2][6..]; - var testName = methodCallLine.Substring(0, methodCallLine.IndexOf(')') + 1); - var lineIndex = methodCallLine.LastIndexOf("line", StringComparison.Ordinal); - var lineNumber = lineIndex > 0 ? methodCallLine[lineIndex..] : ""; + var indexMethodEnding = methodCallLine.IndexOf(')') + 1; + var testName = methodCallLine.Substring(0, indexMethodEnding); + var parts = methodCallLine[indexMethodEnding..].Split(" ", StringSplitOptions.RemoveEmptyEntries); + var fileName = parts[1][..^5]; + var lineNumber = int.Parse(parts[2]); var currentDirectory = Directory.GetCurrentDirectory(); var logFile = currentDirectory.Substring( 0, - currentDirectory.LastIndexOf("\\artifacts\\", StringComparison.Ordinal) + 1) + currentDirectory.LastIndexOf( + $"{Path.DirectorySeparatorChar}artifacts{Path.DirectorySeparatorChar}", + StringComparison.Ordinal) + 1) + "QueryBaseline.txt"; var testInfo = testName + " : " + lineNumber + FileNewLine; - var newBaseLine = $@" AssertSql( {"@\"" + Sql.Replace("\"", "\"\"") + "\""}); "; - var contents = testInfo + newBaseLine + FileNewLine + FileNewLine; + var contents = testInfo + newBaseLine + FileNewLine + "--------------------" + FileNewLine; File.AppendAllText(logFile, contents);