diff --git a/Directory.Build.props b/Directory.Build.props index 67fe2e9d9..437aba492 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -25,6 +25,11 @@ git://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql + + netcoreapp3.1 + netstandard2.0 + + $(MSBuildThisFileDirectory)Pomelo.snk true diff --git a/Pomelo.EntityFrameworkCore.MySql.sln b/Pomelo.EntityFrameworkCore.MySql.sln index f6d7a2d58..03504c44d 100644 --- a/Pomelo.EntityFrameworkCore.MySql.sln +++ b/Pomelo.EntityFrameworkCore.MySql.sln @@ -18,6 +18,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution eng\Development.props.sample = eng\Development.props.sample Directory.Build.props = Directory.Build.props Directory.Build.targets = Directory.Build.targets + global.json = global.json eng\Versions.props = eng\Versions.props EndProjectSection EndProject diff --git a/azure-pipelines.yml b/azure-pipelines.yml index be47a3307..57edda5d7 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -11,6 +11,8 @@ variables: legacy_mysql_mode: STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true DOTNET_CLI_TELEMETRY_OPTOUT: 1 + dotnet_version: 3.1.x + dotnet_ef_tools_version: 3.1.0 jobs: @@ -40,19 +42,25 @@ jobs: pool: vmImage: 'ubuntu-16.04' steps: + - task: UseDotNet@2 + displayName: 'Use .NET Core SDK' + inputs: + version: $(dotnet_version) - bash: | set -e sudo systemctl stop mysql docker run --name mysql -e MYSQL_ROOT_PASSWORD=Password12! -p 3306:3306 -d $DOCKER_IMAGE displayName: Install Database Server - bash: | - dotnet --info + ./dotnet-env.sh dotnet --info + displayName: .NET Core Information + - bash: | set -e cp test/EFCore.MySql.FunctionalTests/config.json.example test/EFCore.MySql.FunctionalTests/config.json cp test/EFCore.MySql.IntegrationTests/appsettings.ci.json test/EFCore.MySql.IntegrationTests/appsettings.json cp test/EFCore.MySql.IntegrationTests/config.json.example test/EFCore.MySql.IntegrationTests/config.json ./build.sh - displayName: Build Solution + displayName: Setup and Build Solution - bash: | started="false" for i in $(seq 0 300); do @@ -69,14 +77,16 @@ jobs: fi docker exec mysql mysql -h localhost -P 3306 -u root -pPassword12! -e "SET GLOBAL sql_mode = '$SQL_MODE';" - - ./dotnet-env.sh dotnet tool install --global dotnet-ef --version 3.0.0 + displayName: Setup Database + - bash: | + ./dotnet-env.sh dotnet tool install --global dotnet-ef --version $(dotnet_ef_tools_version) ./dotnet-env.sh dotnet ef --version - + displayName: Install EF Core Tools + - bash: | if [ "$(INTEGRATION_TESTS)" = "true" ]; then ./dotnet-env.sh ./test/EFCore.MySql.IntegrationTests/scripts/rebuild.sh fi - displayName: Setup Database + displayName: Build Integration Tests - bash: ./dotnet-env.sh dotnet test --logger trx test/EFCore.MySql.Tests displayName: Tests continueOnError: true @@ -139,6 +149,10 @@ jobs: variables: sql_mode: $(current_mysql_mode) steps: + - task: UseDotNet@2 + displayName: 'Use .NET Core SDK' + inputs: + version: $(dotnet_version) - pwsh: | docker run ` -d ` @@ -147,12 +161,15 @@ jobs: -p "3306:3306" ` pomelofoundation/mysql-windows:8-ltsc2019 displayName: Install Database Server + - pwsh: | + .\dotnet-env.ps1 dotnet --info + displayName: .NET Core Information - pwsh: | cp test\EFCore.MySql.FunctionalTests\config.json.example test\EFCore.MySql.FunctionalTests\config.json cp test\EFCore.MySql.IntegrationTests\appsettings.ci.json test\EFCore.MySql.IntegrationTests\appsettings.json cp test\EFCore.MySql.IntegrationTests\config.json.example test\EFCore.MySql.IntegrationTests\config.json .\build.cmd - displayName: Build + displayName: Setup and Build Solution - pwsh: | $started=$false For ($i=0; $i -le 300; $i++) { @@ -169,12 +186,14 @@ jobs: } docker exec mysql mysql -h localhost -u root -pPassword12! -e "SET GLOBAL sql_mode = '$(sql_mode)';" errorActionPreference: continue - displayName: Setup Database 1/2 + displayName: Setup Database - pwsh: | - .\dotnet-env.ps1 dotnet tool install --global dotnet-ef --version 3.0.0 + .\dotnet-env.ps1 dotnet tool install --global dotnet-ef --version $(dotnet_ef_tools_version) .\dotnet-env.ps1 dotnet ef --version + displayName: Install EF Core Tools + - pwsh: | .\dotnet-env.ps1 .\test\EFCore.MySql.IntegrationTests\scripts\rebuild.ps1 - displayName: Setup Database 2/2 + displayName: Build Integration Tests - pwsh: .\dotnet-env.ps1 dotnet test --logger trx test\EFCore.MySql.Tests displayName: Tests continueOnError: true diff --git a/eng/Development.props.sample b/eng/Development.props.sample index 30d755dff..9a9edd9ad 100644 --- a/eng/Development.props.sample +++ b/eng/Development.props.sample @@ -1,9 +1,9 @@ C:\Repositories\EntityFrameworkCore C:\Repositories\MySqlConnector diff --git a/eng/Versions.props b/eng/Versions.props index cb1b0241c..d0455e6dc 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -1,7 +1,7 @@ 3.1.0 - preview3 + rc1 False - 3.0.0 + 3.1.0 - 3.0.1 + 3.1.0 0.61.0 2.2.1 - 3.0.0 - 3.0.0 - 4.6.0 + 3.1.0 + 3.1.0 + 4.7.0 + 3.1.0 + 1.1.0 + 1.1.0 + 3.1.0-rtm.19565.4 + 3.1.0 + 1.7.0 + 4.7.0 16.3.0 2.4.1 @@ -31,22 +38,22 @@ 2.4.1 2.4.1 2.1.26 - 3.0.0 + 3.1.0 - 2.2.4 - 2.2.0 - 2.2.0 + 3.1.0 + 3.1.0 + 3.1.0 4.3.0 - 4.0.0 + 4.4.0 2.0.0 - 3.0.0 - 3.0.0 + 3.1.0 + 3.1.0 - 3.0.0 - 3.3.1 - 3.0.0 - 4.13.0 + 3.1.0 + 3.4.0 + 3.1.0 + 4.13.1 12.0.2 diff --git a/global.json b/global.json index ca73040cf..4b48a1fa4 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "tools": { - "dotnet": "3.0.100", + "dotnet": "3.1.100", "runtimes": { "dotnet": [ "2.0.9", @@ -9,9 +9,9 @@ } }, "sdk": { - "version": "3.0.100" + "version": "3.1.100" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "1.0.0-beta.19461.7" + "Microsoft.DotNet.Arcade.Sdk": "1.0.0-beta.19605.4" } } diff --git a/src/EFCore.MySql/EFCore.MySql.csproj b/src/EFCore.MySql/EFCore.MySql.csproj index 1a1c3b346..cb80c043e 100644 --- a/src/EFCore.MySql/EFCore.MySql.csproj +++ b/src/EFCore.MySql/EFCore.MySql.csproj @@ -2,7 +2,7 @@ MySQL provider for Entity Framework Core - netstandard2.1 + $(DefaultNetStandardTargetFramework) 3.6 Pomelo.EntityFrameworkCore.MySql Pomelo.EntityFrameworkCore.MySql @@ -11,7 +11,7 @@ - $(NoWarn);EF1001 + $(MSBuildWarningsAsMessages);$(NoWarn) @@ -45,8 +45,20 @@ $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Relational.dll - - + + + + + + + + + + + + + + diff --git a/src/EFCore.MySql/Query/ExpressionVisitors/Internal/MySqlQueryTranslationPostprocessor.cs b/src/EFCore.MySql/Query/ExpressionVisitors/Internal/MySqlQueryTranslationPostprocessor.cs index 19e82ae4d..ed392df98 100644 --- a/src/EFCore.MySql/Query/ExpressionVisitors/Internal/MySqlQueryTranslationPostprocessor.cs +++ b/src/EFCore.MySql/Query/ExpressionVisitors/Internal/MySqlQueryTranslationPostprocessor.cs @@ -20,9 +20,8 @@ public MySqlQueryTranslationPostprocessor( public override Expression Process(Expression query) { - query = new MySqlCompatibilityExpressionVisitor(_options).Visit(query); - - return base.Process(query); + query = base.Process(query); + return new MySqlCompatibilityExpressionVisitor(_options).Visit(query); } } } diff --git a/src/EFCore.MySql/Storage/Internal/MySqlDatabaseCreator.cs b/src/EFCore.MySql/Storage/Internal/MySqlDatabaseCreator.cs index cd5c8accb..104145186 100644 --- a/src/EFCore.MySql/Storage/Internal/MySqlDatabaseCreator.cs +++ b/src/EFCore.MySql/Storage/Internal/MySqlDatabaseCreator.cs @@ -113,6 +113,7 @@ public override bool HasTables() new RelationalCommandParameterObject( connection, null, + null, Dependencies.CurrentContext.Context, Dependencies.CommandLogger))) != 0); @@ -130,6 +131,7 @@ public override Task HasTablesAsync(CancellationToken cancellationToken = new RelationalCommandParameterObject( connection, null, + null, Dependencies.CurrentContext.Context, Dependencies.CommandLogger), cancellationToken: ct)) != 0, diff --git a/src/EFCore.MySql/Storage/Internal/ServerVersionSupport.cs b/src/EFCore.MySql/Storage/ServerVersionSupport.cs similarity index 89% rename from src/EFCore.MySql/Storage/Internal/ServerVersionSupport.cs rename to src/EFCore.MySql/Storage/ServerVersionSupport.cs index f8c7be043..4ac442504 100644 --- a/src/EFCore.MySql/Storage/Internal/ServerVersionSupport.cs +++ b/src/EFCore.MySql/Storage/ServerVersionSupport.cs @@ -1,8 +1,8 @@ using System.Linq; -namespace Pomelo.EntityFrameworkCore.MySql.Storage.Internal +namespace Pomelo.EntityFrameworkCore.MySql.Storage { - public partial class ServerVersionSupport + public class ServerVersionSupport { public ServerVersion[] SupportedServerVersions { get; } diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 4014e3cb8..7665b5091 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -2,7 +2,7 @@ - $(NoWarn);CA1822;xUnit1004;EF1001 + $(NoWarn);EF1001;MSB3277;xUnit1000 diff --git a/test/EFCore.MySql.FunctionalTests/BuiltInDataTypesMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/BuiltInDataTypesMySqlTest.cs index 2ddac203f..45035e76c 100644 --- a/test/EFCore.MySql.FunctionalTests/BuiltInDataTypesMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/BuiltInDataTypesMySqlTest.cs @@ -33,26 +33,32 @@ public BuiltInDataTypesMySqlTest(BuiltInDataTypesMySqlFixture fixture, ITestOutp } // Blocked by EF #11929 + [ConditionalFact] public override void Can_query_using_any_data_type() { } + [ConditionalFact] public override void Can_query_using_any_nullable_data_type() { } + [ConditionalFact] public override void Can_query_using_any_nullable_data_type_as_literal() { } + [ConditionalFact] public override void Can_query_using_any_data_type_shadow() { } + [ConditionalFact] public override void Can_query_using_any_data_type_nullable_shadow() { } + [ConditionalFact] public override void Can_perform_query_with_ansi_strings_test() { } @@ -72,7 +78,7 @@ var results Assert.Equal( @"SELECT `m`.`Int` FROM `MappedNullableDataTypes` AS `m` -WHERE (`m`.`TimeSpanAsTime` = '00:01:02') AND `m`.`TimeSpanAsTime` IS NOT NULL", +WHERE `m`.`TimeSpanAsTime` = '00:01:02'", Sql, ignoreLineEndingDifferences: true); } @@ -97,7 +103,7 @@ var results SELECT `m`.`Int` FROM `MappedNullableDataTypes` AS `m` -WHERE ((`m`.`TimeSpanAsTime` = @__timeSpan_0) AND (`m`.`TimeSpanAsTime` IS NOT NULL AND @__timeSpan_0 IS NOT NULL)) OR (`m`.`TimeSpanAsTime` IS NULL AND @__timeSpan_0 IS NULL)", +WHERE `m`.`TimeSpanAsTime` = @__timeSpan_0", Sql, ignoreLineEndingDifferences: true); } @@ -747,46 +753,46 @@ public virtual void Can_insert_and_read_back_all_mapped_data_types_set_to_null() var parameters = DumpParameters(); Assert.Equal( @"@p0='78' -@p1='' (DbType = UInt64) -@p2='' (DbType = SByte) -@p3='' (Size = 6) (DbType = Binary) -@p4='' (Size = 8000) (DbType = Binary) -@p5='' (Size = 255) (DbType = Binary) -@p6='' (DbType = Int32) -@p7='' (Size = 1) -@p8='' (Size = 1) -@p9='' (Size = 1) -@p10='' (DbType = Date) -@p11='' (DbType = DateTime) -@p12='' (Size = 6) (DbType = DateTimeOffset) -@p13='' (Size = 6) (DbType = DateTimeOffset) -@p14='' -@p15='' -@p16='' (DbType = Double) -@p17='' (DbType = Double) -@p18='' (Size = 20) -@p19='' (Size = 20) -@p20='' (DbType = Single) -@p21='' (DbType = Guid) -@p22='' (DbType = Int64) -@p23='' (DbType = Int16) -@p24='' (DbType = SByte) -@p25='' (DbType = Int16) -@p26='' (Size = 20) (DbType = StringFixedLength) -@p27='' (Size = 4000) -@p28='' (Size = 20) (DbType = StringFixedLength) -@p29='' (Size = 4000) -@p30='' (Size = 55) -@p31='' (Size = 55) -@p32='' (Size = 4000) -@p33='' (Size = 55) -@p34='' (DbType = Time) -@p35='' (DbType = Int32) -@p36='' (DbType = Int16) -@p37='' (DbType = Int64) -@p38='' (DbType = Int32) -@p39='' (DbType = Int64) -@p40=''", +@p1=NULL (DbType = UInt64) +@p2=NULL (DbType = SByte) +@p3=NULL (Size = 6) (DbType = Binary) +@p4=NULL (Size = 8000) (DbType = Binary) +@p5=NULL (Size = 255) (DbType = Binary) +@p6=NULL (DbType = Int32) +@p7=NULL (Size = 1) +@p8=NULL (Size = 1) +@p9=NULL (Size = 1) +@p10=NULL (DbType = Date) +@p11=NULL (DbType = DateTime) +@p12=NULL (Size = 6) (DbType = DateTimeOffset) +@p13=NULL (Size = 6) (DbType = DateTimeOffset) +@p14=NULL +@p15=NULL +@p16=NULL (DbType = Double) +@p17=NULL (DbType = Double) +@p18=NULL (Size = 20) +@p19=NULL (Size = 20) +@p20=NULL (DbType = Single) +@p21=NULL (DbType = Guid) +@p22=NULL (DbType = Int64) +@p23=NULL (DbType = Int16) +@p24=NULL (DbType = SByte) +@p25=NULL (DbType = Int16) +@p26=NULL (Size = 20) (DbType = StringFixedLength) +@p27=NULL (Size = 4000) +@p28=NULL (Size = 20) (DbType = StringFixedLength) +@p29=NULL (Size = 4000) +@p30=NULL (Size = 55) +@p31=NULL (Size = 55) +@p32=NULL (Size = 4000) +@p33=NULL (Size = 55) +@p34=NULL (DbType = Time) +@p35=NULL (DbType = Int32) +@p36=NULL (DbType = Int16) +@p37=NULL (DbType = Int64) +@p38=NULL (DbType = Int32) +@p39=NULL (DbType = Int64) +@p40=NULL", parameters, ignoreLineEndingDifferences: true); @@ -907,10 +913,17 @@ public virtual void Columns_have_expected_data_types() var maxKeyLength = AppConfig.ServerVersion.MaxKeyLength; var actual = QueryForColumnTypes(CreateContext(), _testOutputHelper); - var expected = $@"BinaryForeignKeyDataType.BinaryKeyDataTypeId ---> [nullable varbinary] [MaxLength = {maxKeyLength}] + var expected = $@"Animal.Id ---> [int] [Precision = 10 Scale = 0] +AnimalDetails.AnimalId ---> [nullable int] [Precision = 10 Scale = 0] +AnimalDetails.BoolField ---> [int] [Precision = 10 Scale = 0] +AnimalDetails.Id ---> [int] [Precision = 10 Scale = 0] +AnimalIdentification.AnimalId ---> [int] [Precision = 10 Scale = 0] +AnimalIdentification.Id ---> [int] [Precision = 10 Scale = 0] +AnimalIdentification.Method ---> [int] [Precision = 10 Scale = 0] +BinaryForeignKeyDataType.BinaryKeyDataTypeId ---> [nullable varbinary] [MaxLength = 3072] BinaryForeignKeyDataType.Id ---> [int] [Precision = 10 Scale = 0] BinaryKeyDataType.Ex ---> [nullable longtext] [MaxLength = -1] -BinaryKeyDataType.Id ---> [varbinary] [MaxLength = {maxKeyLength}] +BinaryKeyDataType.Id ---> [varbinary] [MaxLength = 3072] BuiltInDataTypes.Enum16 ---> [smallint] [Precision = 5 Scale = 0] BuiltInDataTypes.Enum32 ---> [int] [Precision = 10 Scale = 0] BuiltInDataTypes.Enum64 ---> [bigint] [Precision = 19 Scale = 0] @@ -1190,8 +1203,8 @@ public virtual void Columns_have_expected_data_types() ObjectBackedDataTypes.UnsignedInt32 ---> [int] [Precision = 10 Scale = 0] ObjectBackedDataTypes.UnsignedInt64 ---> [bigint] [Precision = 20 Scale = 0] StringForeignKeyDataType.Id ---> [int] [Precision = 10 Scale = 0] -StringForeignKeyDataType.StringKeyDataTypeId ---> [nullable varchar] [MaxLength = {Math.Min(maxKeyLength / (2 * 4), 255)}] -StringKeyDataType.Id ---> [varchar] [MaxLength = {Math.Min(maxKeyLength / (2 * 4), 255)}] +StringForeignKeyDataType.StringKeyDataTypeId ---> [nullable varchar] [MaxLength = 255] +StringKeyDataType.Id ---> [varchar] [MaxLength = 255] UnicodeDataTypes.Id ---> [int] [Precision = 10 Scale = 0] UnicodeDataTypes.StringAnsi ---> [nullable longtext] [MaxLength = -1] UnicodeDataTypes.StringAnsi3 ---> [nullable varchar] [MaxLength = 3] diff --git a/test/EFCore.MySql.FunctionalTests/ConnectionSettingsMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/ConnectionSettingsMySqlTest.cs index 9ca2a0f3a..9382072d3 100644 --- a/test/EFCore.MySql.FunctionalTests/ConnectionSettingsMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/ConnectionSettingsMySqlTest.cs @@ -45,9 +45,9 @@ public virtual void Insert_and_read_Guid_value(MySqlGuidFormat guidFormat, strin .FromSqlRaw(@"select * from `SimpleGuidEntities` where `GuidValue` = " + string.Format(sqlEquivalent, new Guid("850368D8-93EA-4023-ACC7-6FA6E4C3B27F"))) .ToList(); - Assert.Equal(1, result.Count); + Assert.Single(result); Assert.Equal(new Guid("850368D8-93EA-4023-ACC7-6FA6E4C3B27F"), result[0].GuidValue); - Assert.Equal(1, sqlResult.Count); + Assert.Single(sqlResult); } private readonly IServiceProvider _serviceProvider = new ServiceCollection() diff --git a/test/EFCore.MySql.FunctionalTests/CustomConvertersMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/CustomConvertersMySqlTest.cs index eeccfc719..197e556e8 100644 --- a/test/EFCore.MySql.FunctionalTests/CustomConvertersMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/CustomConvertersMySqlTest.cs @@ -1,8 +1,8 @@ using System; using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests { @@ -13,15 +13,36 @@ public CustomConvertersMySqlTest(CustomConvertersMySqlFixture fixture) { } - // Blocked by EF #11929 + [ConditionalFact(Skip = "EF Core Issue#11929")] public override void Can_query_using_any_data_type_nullable_shadow() { + base.Can_query_using_any_data_type_nullable_shadow(); } + [ConditionalFact(Skip = "EF Core Issue#11929")] public override void Can_perform_query_with_ansi_strings_test() { + base.Can_perform_query_with_ansi_strings_test(); } + [ConditionalFact(Skip = "EF Core Issue#18147")] + public override void Value_conversion_is_appropriately_used_for_join_condition() + { + base.Value_conversion_is_appropriately_used_for_join_condition(); + } + + [ConditionalFact(Skip = "EF Core Issue#18147")] + public override void Value_conversion_is_appropriately_used_for_left_join_condition() + { + base.Value_conversion_is_appropriately_used_for_left_join_condition(); + } + + [ConditionalFact(Skip = "EF Core Issue#18147")] + public override void Where_bool_gets_converted_to_equality_when_value_conversion_is_used() + { + base.Where_bool_gets_converted_to_equality_when_value_conversion_is_used(); + } + public class CustomConvertersMySqlFixture : CustomConvertersFixtureBase { public override bool StrictEquality => true; @@ -38,11 +59,7 @@ public class CustomConvertersMySqlFixture : CustomConvertersFixtureBase public override DateTime DefaultDateTime => new DateTime(); - public override bool SupportsDecimalComparisons => true; // TODO: does it? - - public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder) - => base - .AddOptions(builder); + public override bool SupportsDecimalComparisons => true; } } } diff --git a/test/EFCore.MySql.FunctionalTests/DataAnnotationMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/DataAnnotationMySqlTest.cs index 00105f359..362736c41 100644 --- a/test/EFCore.MySql.FunctionalTests/DataAnnotationMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/DataAnnotationMySqlTest.cs @@ -156,7 +156,7 @@ public override void DatabaseGeneratedAttribute_autogenerates_values_when_set_to { base.DatabaseGeneratedAttribute_autogenerates_values_when_set_to_identity(); - AssertSql(@"@p0='' (Size = 10) + AssertSql(@"@p0=NULL (Size = 10) @p1='Third' (Nullable = false) (Size = 4000) @p2='00000000-0000-0000-0000-000000000003' @p3='Third Additional Name' (Size = 4000) @@ -174,7 +174,7 @@ public override void RequiredAttribute_for_navigation_throws_while_inserting_nul { base.RequiredAttribute_for_navigation_throws_while_inserting_null_value(); - AssertSql(@"@p0='' (DbType = Int32) + AssertSql(@"@p0=NULL (DbType = Int32) @p1='1' INSERT INTO `BookDetails` (`AdditionalBookDetailsId`, `AnotherBookId`) @@ -183,8 +183,8 @@ public override void RequiredAttribute_for_navigation_throws_while_inserting_nul FROM `BookDetails` WHERE ROW_COUNT() = 1 AND `Id` = LAST_INSERT_ID();", ////////////////// - @"@p0='' (DbType = Int32) -@p1='' (Nullable = false) (DbType = Int32) + @"@p0=NULL (DbType = Int32) +@p1=NULL (Nullable = false) (DbType = Int32) INSERT INTO `BookDetails` (`AdditionalBookDetailsId`, `AnotherBookId`) VALUES (@p0, @p1); @@ -197,7 +197,7 @@ public override void RequiredAttribute_for_property_throws_while_inserting_null_ { base.RequiredAttribute_for_property_throws_while_inserting_null_value(); - AssertSql(@"@p0='' (Size = 10) + AssertSql(@"@p0=NULL (Size = 10) @p1='ValidString' (Nullable = false) (Size = 4000) @p2='00000000-0000-0000-0000-000000000001' @p3='Two' (Size = 4000) @@ -209,8 +209,8 @@ public override void RequiredAttribute_for_property_throws_while_inserting_null_ FROM `Sample` WHERE ROW_COUNT() = 1 AND `UniqueNo` = LAST_INSERT_ID();", /////////////////// - @"@p0='' (Size = 10) -@p1='' (Nullable = false) (Size = 4000) + @"@p0=NULL (Size = 10) +@p1=NULL (Nullable = false) (Size = 4000) @p2='00000000-0000-0000-0000-000000000002' @p3='Two' (Size = 4000) @p4='One' (Size = 4000) diff --git a/test/EFCore.MySql.FunctionalTests/EFCore.MySql.FunctionalTests.csproj b/test/EFCore.MySql.FunctionalTests/EFCore.MySql.FunctionalTests.csproj index 908cad396..9da5e99f0 100644 --- a/test/EFCore.MySql.FunctionalTests/EFCore.MySql.FunctionalTests.csproj +++ b/test/EFCore.MySql.FunctionalTests/EFCore.MySql.FunctionalTests.csproj @@ -1,12 +1,16 @@  - netcoreapp3.0 + $(DefaultNetCoreTargetFramework) Pomelo.EntityFrameworkCore.MySql.FunctionalTests Pomelo.EntityFrameworkCore.MySql.FunctionalTests $(DefaultItemExcludes);*.trx + + $(MSBuildWarningsAsMessages);$(NoWarn) + + @@ -51,7 +55,7 @@ - $(LocalMySqlConnectorRepository)\src\MySqlConnector\bin\Debug\$(TargetFramework)\MySqlConnector.dll + $(LocalMySqlConnectorRepository)\src\MySqlConnector\bin\Debug\$(DefaultNetStandardTargetFramework)\MySqlConnector.dll diff --git a/test/EFCore.MySql.FunctionalTests/LazyLoadProxyMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/LazyLoadProxyMySqlTest.cs index a7ea5aecf..ad0a17b3e 100644 --- a/test/EFCore.MySql.FunctionalTests/LazyLoadProxyMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/LazyLoadProxyMySqlTest.cs @@ -1,7 +1,7 @@ using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests { @@ -12,16 +12,31 @@ public LazyLoadProxyMySqlTest(LoadMySqlFixture fixture) { } - public class LoadMySqlFixture : LoadFixtureBase + [ConditionalFact(Skip = "EF Core Issue#1015")] + public override void Top_level_projection_track_entities_before_passing_to_client_method() { - protected override ITestStoreFactory TestStoreFactory => MySqlTestStoreFactory.Instance; + base.Top_level_projection_track_entities_before_passing_to_client_method(); + + Assert.Equal( + @"@__p_0='707' (Nullable = true) + + SELECT [e].[Id], [e].[ParentId] + FROM [Child] AS [e] + WHERE [e].[ParentId] = @__p_0", + Sql, + ignoreLineEndingDifferences: true); + } - protected override bool ShouldLogCategory(string logCategory) - => logCategory == DbLoggerCategory.Query.Name || logCategory == DbLoggerCategory.Database.Command.Name; + protected override void ClearLog() => Fixture.TestSqlLoggerFactory.Clear(); - public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder) - => base.AddOptions(builder) - .EnableDetailedErrors(); + protected override void RecordLog() => Sql = Fixture.TestSqlLoggerFactory.Sql; + + private string Sql { get; set; } + + public class LoadMySqlFixture : LoadFixtureBase + { + public TestSqlLoggerFactory TestSqlLoggerFactory => (TestSqlLoggerFactory)ListLoggerFactory; + protected override ITestStoreFactory TestStoreFactory => MySqlTestStoreFactory.Instance; } } } diff --git a/test/EFCore.MySql.FunctionalTests/MigrationSqlGeneratorMySql55Test.cs b/test/EFCore.MySql.FunctionalTests/MigrationSqlGeneratorMySql55Test.cs index 22ff0695d..b972b96d8 100644 --- a/test/EFCore.MySql.FunctionalTests/MigrationSqlGeneratorMySql55Test.cs +++ b/test/EFCore.MySql.FunctionalTests/MigrationSqlGeneratorMySql55Test.cs @@ -14,12 +14,13 @@ namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests { public class MigrationSqlGeneratorMySql55Test : MigrationSqlGeneratorMySqlTest { + [ConditionalFact] public override void RenameIndexOperation() { Assert.Throws(() => base.RenameIndexOperation()); } - [Fact] + [ConditionalFact] public override void RenameIndexOperation_with_model() { Generate( @@ -44,7 +45,7 @@ public override void RenameIndexOperation_with_model() Sql); } - [Fact] + [ConditionalFact] public override void AddColumnOperation_with_datetime6() { Generate(new AddColumnOperation @@ -62,6 +63,7 @@ public override void AddColumnOperation_with_datetime6() Sql); } + [ConditionalFact] public override void DefaultValue_formats_literal_correctly() { Generate( @@ -89,7 +91,7 @@ public override void DefaultValue_formats_literal_correctly() ignoreLineEndingDifferences: true); } - [Fact] + [ConditionalFact] public override void RenameColumnOperation() { var migrationBuilder = new MigrationBuilder("MySql"); @@ -107,7 +109,7 @@ public override void RenameColumnOperation() Sql); } - [Fact] + [ConditionalFact] public override void RenameColumnOperation_with_model() { var migrationBuilder = new MigrationBuilder("MySql"); diff --git a/test/EFCore.MySql.FunctionalTests/MigrationSqlGeneratorMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/MigrationSqlGeneratorMySqlTest.cs index 1be72d25a..01ee67a62 100644 --- a/test/EFCore.MySql.FunctionalTests/MigrationSqlGeneratorMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/MigrationSqlGeneratorMySqlTest.cs @@ -19,7 +19,7 @@ namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests { public class MigrationSqlGeneratorMySqlTest : MigrationSqlGeneratorTestBase { - [Fact] + [ConditionalFact] public virtual void It_lifts_foreign_key_additions() { Generate( @@ -54,7 +54,7 @@ public virtual void It_lifts_foreign_key_additions() ignoreLineEndingDifferences: true); } - [Fact] + [ConditionalFact] public virtual void DefaultValue_formats_literal_correctly() { Generate( @@ -82,7 +82,7 @@ public virtual void DefaultValue_formats_literal_correctly() ignoreLineEndingDifferences: true); } - [Fact] + [ConditionalFact] public virtual void CreateDatabaseOperation() { Generate(new MySqlCreateDatabaseOperation { Name = "Northwind" }); @@ -92,7 +92,7 @@ public virtual void CreateDatabaseOperation() Sql); } - [Fact] + [ConditionalFact] public override void CreateTableOperation() { base.CreateTableOperation(); @@ -110,7 +110,7 @@ FOREIGN KEY (`EmployerId`) REFERENCES `Companies` (`Id`) ", Sql); } - [Fact] + [ConditionalFact] public virtual void CreateTableUlongAutoincrement() { Generate( @@ -143,7 +143,7 @@ public virtual void CreateTableUlongAutoincrement() Sql); } - [Theory] + [ConditionalTheory] [InlineData(true, false, CharSetBehavior.AppendToAllAnsiColumns, "Latin1", false)] [InlineData(true, false, CharSetBehavior.AppendToUnicodeIndexAndKeyColumns, "Latin1", false)] [InlineData(true, false, CharSetBehavior.AppendToAllUnicodeColumns, "Latin1", true)] @@ -221,6 +221,7 @@ public virtual void AddColumnOperation_with_charSet_implicit(bool? isUnicode, bo Sql); } + [ConditionalFact] public override void AddColumnOperation_with_ansi() { base.AddColumnOperation_with_ansi(); @@ -230,6 +231,7 @@ public override void AddColumnOperation_with_ansi() Sql); } + [ConditionalFact] public override void AddColumnOperation_with_defaultValue() { base.AddColumnOperation_with_defaultValue(); @@ -239,6 +241,7 @@ public override void AddColumnOperation_with_defaultValue() Sql); } + [ConditionalFact] public override void AddColumnOperation_without_column_type() { base.AddColumnOperation_without_column_type(); @@ -248,6 +251,7 @@ public override void AddColumnOperation_without_column_type() Sql); } + [ConditionalFact] public override void AddColumnOperation_with_defaultValueSql() { base.AddColumnOperation_with_defaultValueSql(); @@ -257,7 +261,7 @@ public override void AddColumnOperation_with_defaultValueSql() Sql); } - [Fact] + [ConditionalFact] public virtual void AddColumnOperation_with_datetime6() { Generate(new AddColumnOperation @@ -277,6 +281,7 @@ public virtual void AddColumnOperation_with_datetime6() Sql); } + [ConditionalFact] public override void AddColumnOperation_with_maxLength() { base.AddColumnOperation_with_maxLength(); @@ -286,6 +291,7 @@ public override void AddColumnOperation_with_maxLength() Sql); } + [ConditionalFact] public override void AddColumnOperation_with_maxLength_overridden() { base.AddColumnOperation_with_maxLength_overridden(); @@ -295,6 +301,7 @@ public override void AddColumnOperation_with_maxLength_overridden() Sql); } + [ConditionalFact] public override void AddColumnOperation_with_maxLength_on_derived() { base.AddColumnOperation_with_maxLength_on_derived(); @@ -304,6 +311,7 @@ public override void AddColumnOperation_with_maxLength_on_derived() Sql); } + [ConditionalFact] public override void AddColumnOperation_with_shared_column() { base.AddColumnOperation_with_shared_column(); @@ -313,7 +321,7 @@ public override void AddColumnOperation_with_shared_column() Sql); } - [Fact] + [ConditionalFact] public virtual void AddColumnOperation_with_computed_column() { Generate( @@ -333,7 +341,7 @@ public virtual void AddColumnOperation_with_computed_column() Sql); } - [Fact] + [ConditionalFact] public virtual void AddColumnOperation_serial() { Generate(new AddColumnOperation @@ -351,7 +359,7 @@ public virtual void AddColumnOperation_serial() Sql); } - [Fact] + [ConditionalFact] public virtual void AddColumnOperation_with_int_defaultValue_isnt_serial() { Generate( @@ -370,7 +378,7 @@ public virtual void AddColumnOperation_with_int_defaultValue_isnt_serial() Sql); } - [Fact] + [ConditionalFact] public virtual void AddColumnOperation_with_dbgenerated_uuid() { Generate( @@ -388,7 +396,7 @@ public virtual void AddColumnOperation_with_dbgenerated_uuid() Sql); } - [Fact] + [ConditionalFact] public virtual void AddDefaultDatetimeOperation_with_valueOnUpdate() { Generate( @@ -408,7 +416,7 @@ public virtual void AddDefaultDatetimeOperation_with_valueOnUpdate() Sql); } - [Fact] + [ConditionalFact] public virtual void AddDefaultBooleanOperation() { Generate( @@ -428,7 +436,7 @@ public virtual void AddDefaultBooleanOperation() } - [Theory] + [ConditionalTheory] [InlineData("tinyblob")] [InlineData("blob")] [InlineData("mediumblob")] @@ -489,7 +497,7 @@ public void AlterColumnOperation_with_no_default_value_column_types(string type) Sql); } - [Fact] + [ConditionalFact] public void AlterColumnOperation_type_with_index() { Generate( @@ -520,7 +528,7 @@ public void AlterColumnOperation_type_with_index() Sql); } - [Fact] + [ConditionalFact] public void AlterColumnOperation_ComputedColumnSql_with_index() { Generate( @@ -547,6 +555,7 @@ public void AlterColumnOperation_ComputedColumnSql_with_index() Sql); } + [ConditionalFact] public override void AddForeignKeyOperation_with_name() { base.AddForeignKeyOperation_with_name(); @@ -557,7 +566,7 @@ public override void AddForeignKeyOperation_with_name() Sql); } - [Fact] + [ConditionalFact] public virtual void AddForeignKeyOperation_with_long_name() { Generate( @@ -577,6 +586,7 @@ public virtual void AddForeignKeyOperation_with_long_name() Sql); } + [ConditionalFact] public override void AddForeignKeyOperation_without_name() { base.AddForeignKeyOperation_without_name(); @@ -586,7 +596,7 @@ public override void AddForeignKeyOperation_without_name() Sql); } - [Fact] + [ConditionalFact] public override void AddPrimaryKeyOperation_with_name() { base.AddPrimaryKeyOperation_with_name(); @@ -596,7 +606,7 @@ public override void AddPrimaryKeyOperation_with_name() Sql); } - [Fact] + [ConditionalFact] public override void AddPrimaryKeyOperation_without_name() { base.AddPrimaryKeyOperation_without_name(); @@ -609,7 +619,7 @@ public override void AddPrimaryKeyOperation_without_name() Sql); } - [Fact] + [ConditionalFact] public override void AddUniqueConstraintOperation_with_name() { base.AddUniqueConstraintOperation_with_name(); @@ -620,7 +630,7 @@ public override void AddUniqueConstraintOperation_with_name() Sql); } - [Fact] + [ConditionalFact] public override void AddUniqueConstraintOperation_without_name() { base.AddUniqueConstraintOperation_without_name(); @@ -630,7 +640,7 @@ public override void AddUniqueConstraintOperation_without_name() Sql); } - [Fact] + [ConditionalFact] public override void CreateIndexOperation_unique() { base.CreateIndexOperation_unique(); @@ -640,7 +650,7 @@ public override void CreateIndexOperation_unique() Sql); } - [Fact] + [ConditionalFact] public virtual void CreateIndexOperation_fulltext() { Generate( @@ -657,7 +667,7 @@ public virtual void CreateIndexOperation_fulltext() Sql); } - [Fact] + [ConditionalFact] public virtual void CreateIndexOperation_spatial() { Generate( @@ -674,7 +684,7 @@ public virtual void CreateIndexOperation_spatial() Sql); } - [Fact] + [ConditionalFact] public override void CreateIndexOperation_nonunique() { base.CreateIndexOperation_nonunique(); @@ -684,7 +694,7 @@ public override void CreateIndexOperation_nonunique() Sql); } - [Fact] + [ConditionalFact] public virtual void CreateIndexOperation_with_long_name() { Generate( @@ -701,7 +711,7 @@ public virtual void CreateIndexOperation_with_long_name() Sql); } - [Fact] + [ConditionalFact] public virtual void RenameIndexOperation() { var migrationBuilder = new MigrationBuilder("MySql"); @@ -718,7 +728,7 @@ public virtual void RenameIndexOperation() Sql); } - [Fact] + [ConditionalFact] public virtual void RenameIndexOperation_with_model() { Generate( @@ -741,7 +751,7 @@ public virtual void RenameIndexOperation_with_model() Sql); } - [Fact] + [ConditionalFact] public virtual void RenameColumnOperation() { var migrationBuilder = new MigrationBuilder("MySql"); @@ -758,7 +768,7 @@ public virtual void RenameColumnOperation() Sql); } - [Fact] + [ConditionalFact] public virtual void RenameColumnOperation_with_model() { var migrationBuilder = new MigrationBuilder("MySql"); @@ -779,7 +789,7 @@ public virtual void RenameColumnOperation_with_model() Sql); } - [Fact] + [ConditionalFact] public override void DropColumnOperation() { base.DropColumnOperation(); @@ -789,7 +799,7 @@ public override void DropColumnOperation() Sql); } - [Fact] + [ConditionalFact] public override void DropForeignKeyOperation() { base.DropForeignKeyOperation(); @@ -799,7 +809,7 @@ public override void DropForeignKeyOperation() Sql); } - [Fact] + [ConditionalFact] public override void DropPrimaryKeyOperation() { base.DropPrimaryKeyOperation(); @@ -810,7 +820,7 @@ public override void DropPrimaryKeyOperation() Sql); } - [Fact] + [ConditionalFact] public override void DropTableOperation() { base.DropTableOperation(); @@ -820,7 +830,7 @@ public override void DropTableOperation() Sql); } - [Fact] + [ConditionalFact] public override void DropUniqueConstraintOperation() { base.DropUniqueConstraintOperation(); @@ -830,6 +840,7 @@ public override void DropUniqueConstraintOperation() Sql); } + [ConditionalFact] public override void DropIndexOperation() { base.DropIndexOperation(); @@ -839,7 +850,7 @@ public override void DropIndexOperation() Sql); } - [Fact] + [ConditionalFact] public override void SqlOperation() { base.SqlOperation(); @@ -849,7 +860,7 @@ public override void SqlOperation() Sql); } - [Fact] + [ConditionalFact] public virtual void AddColumnOperation_with_charSet_annotation() { Generate( @@ -870,26 +881,32 @@ public virtual void AddColumnOperation_with_charSet_annotation() } // MySql doesn't support sequence + [ConditionalFact] public override void AlterSequenceOperation_with_minValue_and_maxValue() { } + [ConditionalFact] public override void AlterSequenceOperation_without_minValue_and_maxValue() { } + [ConditionalFact] public override void CreateSequenceOperation_with_minValue_and_maxValue() { } + [ConditionalFact] public override void CreateSequenceOperation_with_minValue_and_maxValue_not_long() { } + [ConditionalFact] public override void CreateSequenceOperation_without_minValue_and_maxValue() { } + [ConditionalFact] public override void DropSequenceOperation() { } diff --git a/test/EFCore.MySql.FunctionalTests/Query/ComplexNavigationsQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/ComplexNavigationsQueryMySqlTest.cs index 4805cd6c4..8dd598638 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/ComplexNavigationsQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/ComplexNavigationsQueryMySqlTest.cs @@ -16,11 +16,45 @@ public ComplexNavigationsQueryMySqlTest(ComplexNavigationsQueryMySqlFixture fixt //Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); } + [SupportedServerVersionTheory(ServerVersion.OuterApplySupportKey)] + [MemberData(nameof(IsAsyncData))] + public override Task Include_inside_subquery(bool isAsync) + { + return base.Include_inside_subquery(isAsync); + } + + [SupportedServerVersionTheory(ServerVersion.OuterApplySupportKey)] + [MemberData(nameof(IsAsyncData))] + public override Task Project_collection_navigation_nested_with_take(bool isAsync) + { + return base.Project_collection_navigation_nested_with_take(isAsync); + } + [SupportedServerVersionTheory(ServerVersion.WindowFunctionsSupportKey)] [MemberData(nameof(IsAsyncData))] public override Task SelectMany_with_navigation_filter_paging_and_explicit_DefaultIfEmpty(bool isAsync) { return base.SelectMany_with_navigation_filter_paging_and_explicit_DefaultIfEmpty(isAsync); } + + [SupportedServerVersionTheory(ServerVersion.WindowFunctionsSupportKey)] + [MemberData(nameof(IsAsyncData))] + public override Task Including_reference_navigation_and_projecting_collection_navigation_2(bool isAsync) + { + return base.Including_reference_navigation_and_projecting_collection_navigation_2(isAsync); + } + + [SupportedServerVersionTheory(ServerVersion.WindowFunctionsSupportKey)] + [MemberData(nameof(IsAsyncData))] + public override Task Lift_projection_mapping_when_pushing_down_subquery(bool isAsync) + { + return base.Lift_projection_mapping_when_pushing_down_subquery(isAsync); + } + + [SupportedServerVersionFact(ServerVersion.WindowFunctionsSupportKey)] + public override void Member_pushdown_chain_3_levels_deep_entity() + { + base.Member_pushdown_chain_3_levels_deep_entity(); + } } } diff --git a/test/EFCore.MySql.FunctionalTests/Query/ComplexNavigationsWeakQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/ComplexNavigationsWeakQueryMySqlTest.cs index 78b5863b0..97bbfc2c5 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/ComplexNavigationsWeakQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/ComplexNavigationsWeakQueryMySqlTest.cs @@ -16,11 +16,32 @@ public ComplexNavigationsWeakQueryMySqlTest(ComplexNavigationsWeakQueryMySqlFixt //Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); } + [SupportedServerVersionTheory(ServerVersion.WindowFunctionsSupportKey)] + [MemberData(nameof(IsAsyncData))] + public override Task Including_reference_navigation_and_projecting_collection_navigation_2(bool isAsync) + { + return base.Including_reference_navigation_and_projecting_collection_navigation_2(isAsync); + } + + [SupportedServerVersionTheory(ServerVersion.WindowFunctionsSupportKey)] + [MemberData(nameof(IsAsyncData))] + public override Task Lift_projection_mapping_when_pushing_down_subquery(bool isAsync) + { + return base.Lift_projection_mapping_when_pushing_down_subquery(isAsync); + } + [SupportedServerVersionTheory(ServerVersion.WindowFunctionsSupportKey)] [MemberData(nameof(IsAsyncData))] public override Task SelectMany_with_navigation_filter_paging_and_explicit_DefaultIfEmpty(bool isAsync) { return base.SelectMany_with_navigation_filter_paging_and_explicit_DefaultIfEmpty(isAsync); } + + [SupportedServerVersionTheory(ServerVersion.OuterApplySupportKey)] + [MemberData(nameof(IsAsyncData))] + public override Task Project_collection_navigation_nested_with_take(bool isAsync) + { + return base.Project_collection_navigation_nested_with_take(isAsync); + } } } diff --git a/test/EFCore.MySql.FunctionalTests/Query/DbFunctionsMySqlTest.MySql.cs b/test/EFCore.MySql.FunctionalTests/Query/DbFunctionsMySqlTest.MySql.cs index cefdaf9f6..a929197cd 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/DbFunctionsMySqlTest.MySql.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/DbFunctionsMySqlTest.MySql.cs @@ -22,7 +22,7 @@ public virtual void DateDiff_Year() AssertSql( @"SELECT COUNT(*) FROM `Orders` AS `o` -WHERE (TIMESTAMPDIFF(YEAR, `o`.`OrderDate`, CURRENT_TIMESTAMP()) = 0) AND TIMESTAMPDIFF(YEAR, `o`.`OrderDate`, CURRENT_TIMESTAMP()) IS NOT NULL"); +WHERE TIMESTAMPDIFF(YEAR, `o`.`OrderDate`, CURRENT_TIMESTAMP()) = 0"); } } @@ -39,7 +39,7 @@ public virtual void DateDiff_Month() AssertSql( @"SELECT COUNT(*) FROM `Orders` AS `o` -WHERE (TIMESTAMPDIFF(MONTH, `o`.`OrderDate`, CURRENT_TIMESTAMP()) = 0) AND TIMESTAMPDIFF(MONTH, `o`.`OrderDate`, CURRENT_TIMESTAMP()) IS NOT NULL"); +WHERE TIMESTAMPDIFF(MONTH, `o`.`OrderDate`, CURRENT_TIMESTAMP()) = 0"); } } @@ -56,7 +56,7 @@ public virtual void DateDiff_Day() AssertSql( @"SELECT COUNT(*) FROM `Orders` AS `o` -WHERE (TIMESTAMPDIFF(DAY, `o`.`OrderDate`, CURRENT_TIMESTAMP()) = 0) AND TIMESTAMPDIFF(DAY, `o`.`OrderDate`, CURRENT_TIMESTAMP()) IS NOT NULL"); +WHERE TIMESTAMPDIFF(DAY, `o`.`OrderDate`, CURRENT_TIMESTAMP()) = 0"); } } @@ -73,7 +73,7 @@ public virtual void DateDiff_Hour() AssertSql( @"SELECT COUNT(*) FROM `Orders` AS `o` -WHERE (TIMESTAMPDIFF(HOUR, `o`.`OrderDate`, CURRENT_TIMESTAMP()) = 0) AND TIMESTAMPDIFF(HOUR, `o`.`OrderDate`, CURRENT_TIMESTAMP()) IS NOT NULL"); +WHERE TIMESTAMPDIFF(HOUR, `o`.`OrderDate`, CURRENT_TIMESTAMP()) = 0"); } } @@ -90,7 +90,7 @@ public virtual void DateDiff_Minute() AssertSql( @"SELECT COUNT(*) FROM `Orders` AS `o` -WHERE (TIMESTAMPDIFF(MINUTE, `o`.`OrderDate`, CURRENT_TIMESTAMP()) = 0) AND TIMESTAMPDIFF(MINUTE, `o`.`OrderDate`, CURRENT_TIMESTAMP()) IS NOT NULL"); +WHERE TIMESTAMPDIFF(MINUTE, `o`.`OrderDate`, CURRENT_TIMESTAMP()) = 0"); } } @@ -107,7 +107,7 @@ public virtual void DateDiff_Second() AssertSql( @"SELECT COUNT(*) FROM `Orders` AS `o` -WHERE (TIMESTAMPDIFF(SECOND, `o`.`OrderDate`, CURRENT_TIMESTAMP()) = 0) AND TIMESTAMPDIFF(SECOND, `o`.`OrderDate`, CURRENT_TIMESTAMP()) IS NOT NULL"); +WHERE TIMESTAMPDIFF(SECOND, `o`.`OrderDate`, CURRENT_TIMESTAMP()) = 0"); } } diff --git a/test/EFCore.MySql.FunctionalTests/Query/DbFunctionsMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/DbFunctionsMySqlTest.cs index a0caaf770..2e48e4920 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/DbFunctionsMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/DbFunctionsMySqlTest.cs @@ -1,5 +1,6 @@ using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; using Xunit.Abstractions; namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query @@ -12,6 +13,7 @@ public DbFunctionsMySqlTest(NorthwindQueryMySqlFixture fixt Fixture.TestSqlLoggerFactory.Clear(); } + [ConditionalFact] public override void Like_literal() { base.Like_literal(); @@ -22,6 +24,7 @@ public override void Like_literal() WHERE `c`.`ContactName` LIKE '%M%'"); } + [ConditionalFact] public override void Like_identity() { base.Like_identity(); @@ -32,6 +35,7 @@ public override void Like_identity() WHERE `c`.`ContactName` LIKE `c`.`ContactName`"); } + [ConditionalFact] public override void Like_literal_with_escape() { base.Like_literal_with_escape(); diff --git a/test/EFCore.MySql.FunctionalTests/Query/EscapesMySqlNoBackslashesTest.cs b/test/EFCore.MySql.FunctionalTests/Query/EscapesMySqlNoBackslashesTest.cs index 11931b8af..62eb83397 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/EscapesMySqlNoBackslashesTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/EscapesMySqlNoBackslashesTest.cs @@ -27,16 +27,16 @@ public override void Input_query_escapes_parameter() AssertSql( $@"@p0='ESCBCKSLINS' (Nullable = false) (Size = {Math.Min(AppConfig.ServerVersion.MaxKeyLength / (2 * 4), 255)}) -@p1='' (Size = 4000) -@p2='' (Size = 4000) +@p1=NULL (Size = 4000) +@p2=NULL (Size = 4000) @p3='Back\slash's Insert Operation' (Size = 4000) -@p4='' (Size = 4000) -@p5='' (Size = 4000) -@p6='' (Size = 4000) -@p7='' (Size = 4000) -@p8='' (Size = 4000) -@p9='' (Size = 4000) -@p10='' (Size = 4000) +@p4=NULL (Size = 4000) +@p5=NULL (Size = 4000) +@p6=NULL (Size = 4000) +@p7=NULL (Size = 4000) +@p8=NULL (Size = 4000) +@p9=NULL (Size = 4000) +@p10=NULL (Size = 4000) INSERT INTO `Customers` (`CustomerID`, `Address`, `City`, `CompanyName`, `ContactName`, `ContactTitle`, `Country`, `Fax`, `Phone`, `PostalCode`, `Region`) VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10);", @@ -47,6 +47,7 @@ public override void Input_query_escapes_parameter() } [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_query_escapes_literal(bool isAsync) { await base.Where_query_escapes_literal(isAsync); @@ -54,10 +55,11 @@ public override async Task Where_query_escapes_literal(bool isAsync) AssertSql( @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE (`c`.`CompanyName` = 'Back\slash''s Operation') AND `c`.`CompanyName` IS NOT NULL"); +WHERE `c`.`CompanyName` = 'Back\slash''s Operation'"); } [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_query_escapes_parameter(bool isAsync) { await base.Where_query_escapes_parameter(isAsync); @@ -67,10 +69,11 @@ public override async Task Where_query_escapes_parameter(bool isAsync) SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE ((`c`.`CompanyName` = @__companyName_0) AND (`c`.`CompanyName` IS NOT NULL AND @__companyName_0 IS NOT NULL)) OR (`c`.`CompanyName` IS NULL AND @__companyName_0 IS NULL)"); +WHERE `c`.`CompanyName` = @__companyName_0"); } [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_contains_query_escapes(bool isAsync) { await base.Where_contains_query_escapes(isAsync); diff --git a/test/EFCore.MySql.FunctionalTests/Query/EscapesMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/EscapesMySqlTest.cs index 1a0059a77..a18ed9f6c 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/EscapesMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/EscapesMySqlTest.cs @@ -27,16 +27,16 @@ public override void Input_query_escapes_parameter() AssertSql( $@"@p0='ESCBCKSLINS' (Nullable = false) (Size = {Math.Min(AppConfig.ServerVersion.MaxKeyLength / (2 * 4), 255)}) -@p1='' (Size = 4000) -@p2='' (Size = 4000) +@p1=NULL (Size = 4000) +@p2=NULL (Size = 4000) @p3='Back\slash's Insert Operation' (Size = 4000) -@p4='' (Size = 4000) -@p5='' (Size = 4000) -@p6='' (Size = 4000) -@p7='' (Size = 4000) -@p8='' (Size = 4000) -@p9='' (Size = 4000) -@p10='' (Size = 4000) +@p4=NULL (Size = 4000) +@p5=NULL (Size = 4000) +@p6=NULL (Size = 4000) +@p7=NULL (Size = 4000) +@p8=NULL (Size = 4000) +@p9=NULL (Size = 4000) +@p10=NULL (Size = 4000) INSERT INTO `Customers` (`CustomerID`, `Address`, `City`, `CompanyName`, `ContactName`, `ContactTitle`, `Country`, `Fax`, `Phone`, `PostalCode`, `Region`) VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10);", @@ -47,6 +47,7 @@ public override void Input_query_escapes_parameter() } [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_query_escapes_literal(bool isAsync) { await base.Where_query_escapes_literal(isAsync); @@ -54,10 +55,11 @@ public override async Task Where_query_escapes_literal(bool isAsync) AssertSql( @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE (`c`.`CompanyName` = 'Back\\slash''s Operation') AND `c`.`CompanyName` IS NOT NULL"); +WHERE `c`.`CompanyName` = 'Back\\slash''s Operation'"); } [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_query_escapes_parameter(bool isAsync) { await base.Where_query_escapes_parameter(isAsync); @@ -67,10 +69,11 @@ public override async Task Where_query_escapes_parameter(bool isAsync) SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE ((`c`.`CompanyName` = @__companyName_0) AND (`c`.`CompanyName` IS NOT NULL AND @__companyName_0 IS NOT NULL)) OR (`c`.`CompanyName` IS NULL AND @__companyName_0 IS NULL)"); +WHERE `c`.`CompanyName` = @__companyName_0"); } [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_contains_query_escapes(bool isAsync) { await base.Where_contains_query_escapes(isAsync); diff --git a/test/EFCore.MySql.FunctionalTests/Query/EscapesMySqlTestBase.cs b/test/EFCore.MySql.FunctionalTests/Query/EscapesMySqlTestBase.cs index ab510c36b..eb7166895 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/EscapesMySqlTestBase.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/EscapesMySqlTestBase.cs @@ -38,7 +38,7 @@ public virtual void Input_query_escapes_parameter() context => { var customers = context.Customers.Where(x => x.CustomerID == "ESCBCKSLINS").ToList(); - Assert.Equal(1, customers.Count); + Assert.Single(customers); Assert.True(customers[0].CompanyName == @"Back\slash's Insert Operation"); }); } @@ -55,7 +55,7 @@ public virtual async Task Where_query_escapes_literal(bool isAsync) ? await query.ToListAsync() : query.ToList(); - Assert.Equal(1, customers.Count); + Assert.Single(customers); } } @@ -73,7 +73,7 @@ public virtual async Task Where_query_escapes_parameter(bool isAsync) ? await query.ToListAsync() : query.ToList(); - Assert.Equal(1, customers.Count); + Assert.Single(customers); } } diff --git a/test/EFCore.MySql.FunctionalTests/Query/FiltersMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/FiltersMySqlTest.cs index 35e0c65ad..6e7612d9b 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/FiltersMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/FiltersMySqlTest.cs @@ -21,7 +21,7 @@ public override void Count_query() SELECT COUNT(*) FROM `Customers` AS `c` -WHERE ((@__ef_filter__TenantPrefix_0 = '') AND @__ef_filter__TenantPrefix_0 IS NOT NULL) OR (`c`.`CompanyName` IS NOT NULL AND (@__ef_filter__TenantPrefix_0 IS NOT NULL AND ((`c`.`CompanyName` LIKE CONCAT(@__ef_filter__TenantPrefix_0, '%')) AND (((LEFT(`c`.`CompanyName`, CHAR_LENGTH(CONVERT(@__ef_filter__TenantPrefix_0 USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT(@__ef_filter__TenantPrefix_0 USING utf8mb4) COLLATE utf8mb4_bin) AND (LEFT(`c`.`CompanyName`, CHAR_LENGTH(CONVERT(@__ef_filter__TenantPrefix_0 USING utf8mb4) COLLATE utf8mb4_bin)) IS NOT NULL AND CONVERT(@__ef_filter__TenantPrefix_0 USING utf8mb4) COLLATE utf8mb4_bin IS NOT NULL)) OR (LEFT(`c`.`CompanyName`, CHAR_LENGTH(CONVERT(@__ef_filter__TenantPrefix_0 USING utf8mb4) COLLATE utf8mb4_bin)) IS NULL AND CONVERT(@__ef_filter__TenantPrefix_0 USING utf8mb4) COLLATE utf8mb4_bin IS NULL)))))"); +WHERE (@__ef_filter__TenantPrefix_0 = '') OR (`c`.`CompanyName` IS NOT NULL AND ((`c`.`CompanyName` LIKE CONCAT(@__ef_filter__TenantPrefix_0, '%')) AND ((LEFT(`c`.`CompanyName`, CHAR_LENGTH(CONVERT(@__ef_filter__TenantPrefix_0 USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT(@__ef_filter__TenantPrefix_0 USING utf8mb4) COLLATE utf8mb4_bin) OR (LEFT(`c`.`CompanyName`, CHAR_LENGTH(CONVERT(@__ef_filter__TenantPrefix_0 USING utf8mb4) COLLATE utf8mb4_bin)) IS NULL AND CONVERT(@__ef_filter__TenantPrefix_0 USING utf8mb4) COLLATE utf8mb4_bin IS NULL))))"); } private void AssertSql(params string[] expected) diff --git a/test/EFCore.MySql.FunctionalTests/Query/FromSqlQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/FromSqlQueryMySqlTest.cs index 409a31847..22b305312 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/FromSqlQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/FromSqlQueryMySqlTest.cs @@ -37,7 +37,7 @@ public override void FromSqlRaw_queryable_simple_projection_composed() { var boolMapping = (RelationalTypeMapping)context.GetService().FindMapping(typeof(bool)); var actual = context.Set().FromSqlRaw( - NormalizeDelimetersInRawString( + NormalizeDelimitersInRawString( @"SELECT * FROM [Products] WHERE [Discontinued] <> " + boolMapping.GenerateSqlLiteral(true))) diff --git a/test/EFCore.MySql.FunctionalTests/Query/FromSqlSprocQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/FromSqlSprocQueryMySqlTest.cs index a0bdeea27..91b16e36c 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/FromSqlSprocQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/FromSqlSprocQueryMySqlTest.cs @@ -21,69 +21,7 @@ public FromSqlSprocQueryMySqlTest( fixture.TestSqlLoggerFactory.Clear(); } - public override async Task From_sql_queryable_stored_procedure_re_projection(bool async) - { - // MySQL does not support SELECT on a stored procedure's result set. - return AssertSqlException(await base.From_sql_queryable_stored_procedure_re_projection(async)); - } - - public override async Task From_sql_queryable_stored_procedure_composed(bool async) - { - // MySQL does not support WHERE on a stored procedure's result set. - return AssertSqlException(await base.From_sql_queryable_stored_procedure_composed(async)); - } - - public override async Task From_sql_queryable_stored_procedure_with_parameter_composed(bool async) - { - // MySQL does not support WHERE on a stored procedure's result set. - return AssertSqlException(await base.From_sql_queryable_stored_procedure_with_parameter_composed(async)); - } - - public override async Task From_sql_queryable_stored_procedure_take(bool async) - { - // MySQL does not support ORDER BY on a stored procedure's result set. - return AssertSqlException(await base.From_sql_queryable_stored_procedure_take(async)); - } - - public override async Task From_sql_queryable_stored_procedure_min(bool async) - { - // MySQL does not support GROUP BY/MIN() on a stored procedure's result set. - return AssertSqlException(await base.From_sql_queryable_stored_procedure_min(async)); - } - - public override async Task From_sql_queryable_stored_procedure_with_include_throws(bool async) - { - // MySQL does not support JOIN on a stored procedure's result set. - return AssertSqlException(await base.From_sql_queryable_stored_procedure_with_include_throws(async)); - } - - public override async Task From_sql_queryable_with_multiple_stored_procedures(bool async) - { - // MySQL does neither support calling multiple stored procedures in a query, nor does it support - // SELECT on multiple stored procedure result sets. - return AssertSqlException(await base.From_sql_queryable_with_multiple_stored_procedures(async)); - } - - public override async Task From_sql_queryable_stored_procedure_and_select(bool async) - { - // MySQL does not support WHERE on a stored procedure's result set. - return AssertSqlException(await base.From_sql_queryable_stored_procedure_and_select(async)); - } - - public override async Task From_sql_queryable_select_and_stored_procedure(bool async) - { - // MySQL does not support WHERE on a stored procedure's result set. - return AssertSqlException(await base.From_sql_queryable_select_and_stored_procedure(async)); - } - protected override string TenMostExpensiveProductsSproc => "CALL `Ten Most Expensive Products`()"; protected override string CustomerOrderHistorySproc => "CALL `CustOrderHist` ({0})"; - - private static T AssertSqlException(Exception exception) - where T : Exception - { - Assert.IsType(exception); - return (T)exception; - } } } diff --git a/test/EFCore.MySql.FunctionalTests/Query/GearsOfWarQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/GearsOfWarQueryMySqlTest.cs index 7aa908e95..7ce4f6a38 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/GearsOfWarQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/GearsOfWarQueryMySqlTest.cs @@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.TestModels.GearsOfWarModel; +using Microsoft.EntityFrameworkCore.TestUtilities; using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities.Attributes; using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities.Extensions; using Pomelo.EntityFrameworkCore.MySql.Storage; @@ -29,15 +30,15 @@ public GearsOfWarQueryMySqlTest(GearsOfWarQueryMySqlFixture fixture, ITestOutput } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Where_datetimeoffset_now(bool isAsync) { return AssertQuery( isAsync, - ms => from m in ms + ss => from m in ss.Set() where m.Timeline != DateTimeOffset.Now select m, - ms => from m in ms + ss => from m in ss.Set() where m.Timeline.SimulateDatabaseRoundtrip(_typeMappingSource) != DateTimeOffset.Now select new Mission() { @@ -50,15 +51,15 @@ where m.Timeline.SimulateDatabaseRoundtrip(_typeMappingSource) != DateTimeOffset } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Where_datetimeoffset_utcnow(bool isAsync) { return AssertQuery( isAsync, - ms => from m in ms + ss => from m in ss.Set() where m.Timeline != DateTimeOffset.UtcNow select m, - ms => from m in ms + ss => from m in ss.Set() where m.Timeline.SimulateDatabaseRoundtrip(_typeMappingSource) != DateTimeOffset.UtcNow select new Mission() { @@ -71,15 +72,15 @@ where m.Timeline.SimulateDatabaseRoundtrip(_typeMappingSource) != DateTimeOffset } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Where_datetimeoffset_date_component(bool isAsync) { return AssertQuery( isAsync, - ms => from m in ms + ss => from m in ss.Set() where m.Timeline.Date > new DateTimeOffset().Date select m, - ms => from m in ms + ss => from m in ss.Set() where m.Timeline.SimulateDatabaseRoundtrip(_typeMappingSource).Date > new DateTimeOffset().SimulateDatabaseRoundtrip(_typeMappingSource).Date select new Mission() { @@ -92,15 +93,15 @@ public override Task Where_datetimeoffset_date_component(bool isAsync) } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Where_datetimeoffset_year_component(bool isAsync) { return AssertQuery( isAsync, - ms => from m in ms + ss => from m in ss.Set() where m.Timeline.Year == 2 select m, - ms => from m in ms + ss => from m in ss.Set() where m.Timeline.SimulateDatabaseRoundtrip(_typeMappingSource).Year == 2 select new Mission() { @@ -113,15 +114,15 @@ where m.Timeline.SimulateDatabaseRoundtrip(_typeMappingSource).Year == 2 } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Where_datetimeoffset_month_component(bool isAsync) { return AssertQuery( isAsync, - ms => from m in ms + ss => from m in ss.Set() where m.Timeline.Month == 1 select m, - ms => from m in ms + ss => from m in ss.Set() where m.Timeline.SimulateDatabaseRoundtrip(_typeMappingSource).Month == 1 select new Mission() { @@ -134,15 +135,15 @@ where m.Timeline.SimulateDatabaseRoundtrip(_typeMappingSource).Month == 1 } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Where_datetimeoffset_dayofyear_component(bool isAsync) { return AssertQuery( isAsync, - ms => from m in ms + ss => from m in ss.Set() where m.Timeline.DayOfYear == 2 select m, - ms => from m in ms + ss => from m in ss.Set() where m.Timeline.SimulateDatabaseRoundtrip(_typeMappingSource).DayOfYear == 2 select new Mission() { @@ -155,15 +156,15 @@ where m.Timeline.SimulateDatabaseRoundtrip(_typeMappingSource).DayOfYear == 2 } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Where_datetimeoffset_day_component(bool isAsync) { return AssertQuery( isAsync, - ms => from m in ms + ss => from m in ss.Set() where m.Timeline.Day == 2 select m, - ms => from m in ms + ss => from m in ss.Set() where m.Timeline.SimulateDatabaseRoundtrip(_typeMappingSource).Day == 2 select new Mission() { @@ -176,15 +177,15 @@ where m.Timeline.SimulateDatabaseRoundtrip(_typeMappingSource).Day == 2 } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Where_datetimeoffset_hour_component(bool isAsync) { return AssertQuery( isAsync, - ms => from m in ms + ss => from m in ss.Set() where m.Timeline.Hour == 10 select m, - ms => from m in ms + ss => from m in ss.Set() where m.Timeline.SimulateDatabaseRoundtrip(_typeMappingSource).Hour == 10 select new Mission() { @@ -197,15 +198,15 @@ where m.Timeline.SimulateDatabaseRoundtrip(_typeMappingSource).Hour == 10 } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Where_datetimeoffset_minute_component(bool isAsync) { return AssertQuery( isAsync, - ms => from m in ms + ss => from m in ss.Set() where m.Timeline.Minute == 0 select m, - ms => from m in ms + ss => from m in ss.Set() where m.Timeline.SimulateDatabaseRoundtrip(_typeMappingSource).Minute == 0 select new Mission() { @@ -218,15 +219,15 @@ where m.Timeline.SimulateDatabaseRoundtrip(_typeMappingSource).Minute == 0 } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Where_datetimeoffset_second_component(bool isAsync) { return AssertQuery( isAsync, - ms => from m in ms + ss => from m in ss.Set() where m.Timeline.Second == 0 select m, - ms => from m in ms + ss => from m in ss.Set() where m.Timeline.SimulateDatabaseRoundtrip(_typeMappingSource).Second == 0 select new Mission() { @@ -239,15 +240,15 @@ where m.Timeline.SimulateDatabaseRoundtrip(_typeMappingSource).Second == 0 } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Where_datetimeoffset_millisecond_component(bool isAsync) { return AssertQuery( isAsync, - ms => from m in ms + ss => from m in ss.Set() where m.Timeline.Millisecond == 0 select m, - ms => from m in ms + ss => from m in ss.Set() where m.Timeline.SimulateDatabaseRoundtrip(_typeMappingSource).Millisecond == 0 select new Mission() { @@ -259,96 +260,90 @@ where m.Timeline.SimulateDatabaseRoundtrip(_typeMappingSource).Millisecond == 0 }); } - [ConditionalFact] - public override void Where_datetimeoffset_milliseconds_parameter_and_constant() - { - base.Where_datetimeoffset_milliseconds_parameter_and_constant(); - } - [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task DateTimeOffset_DateAdd_AddYears(bool isAsync) { - return AssertQueryScalar( + return AssertQueryScalar( isAsync, - ms => from m in ms + ss => from m in ss.Set() select m.Timeline.AddYears(1)); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task DateTimeOffset_DateAdd_AddMonths(bool isAsync) { - return AssertQueryScalar( + return AssertQueryScalar( isAsync, - ms => from m in ms + ss => from m in ss.Set() select m.Timeline.AddMonths(1)); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task DateTimeOffset_DateAdd_AddDays(bool isAsync) { - return AssertQueryScalar( + return AssertQueryScalar( isAsync, - ms => from m in ms + ss => from m in ss.Set() select m.Timeline.AddDays(1)); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task DateTimeOffset_DateAdd_AddHours(bool isAsync) { - return AssertQueryScalar( + return AssertQueryScalar( isAsync, - ms => from m in ms + ss => from m in ss.Set() select m.Timeline.AddHours(1)); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task DateTimeOffset_DateAdd_AddMinutes(bool isAsync) { - return AssertQueryScalar( + return AssertQueryScalar( isAsync, - ms => from m in ms + ss => from m in ss.Set() select m.Timeline.AddMinutes(1)); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task DateTimeOffset_DateAdd_AddSeconds(bool isAsync) { - return AssertQueryScalar( + return AssertQueryScalar( isAsync, - ms => from m in ms + ss => from m in ss.Set() select m.Timeline.AddSeconds(1)); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task DateTimeOffset_DateAdd_AddMilliseconds(bool isAsync) { - return AssertQueryScalar( + return AssertQueryScalar( isAsync, - ms => from m in ms + ss => from m in ss.Set() select m.Timeline.AddMilliseconds(300)); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Time_of_day_datetimeoffset(bool isAsync) { - return AssertQueryScalar( + return AssertQueryScalar( isAsync, - ms => from m in ms + ss => from m in ss.Set() select m.Timeline.TimeOfDay, - ms => from m in ms + ss => from m in ss.Set() select m.Timeline.SimulateDatabaseRoundtrip(_typeMappingSource).TimeOfDay); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task DateTimeOffset_Contains_Less_than_Greater_than(bool isAsync) { var dto = new DateTimeOffset(599898024001234567, new TimeSpan(1, 30, 0)); @@ -358,10 +353,10 @@ public override Task DateTimeOffset_Contains_Less_than_Greater_than(bool isAsync return AssertQuery( isAsync, - ms => ms.Where(m => start <= m.Timeline.Date && + ss => ss.Set().Where(m => start <= m.Timeline.Date && m.Timeline < end && dates.Contains(m.Timeline)), - ms => ms.Where(m => start.SimulateDatabaseRoundtrip(_typeMappingSource) <= m.Timeline.SimulateDatabaseRoundtrip(_typeMappingSource).Date && + ss => ss.Set().Where(m => start.SimulateDatabaseRoundtrip(_typeMappingSource) <= m.Timeline.SimulateDatabaseRoundtrip(_typeMappingSource).Date && m.Timeline.SimulateDatabaseRoundtrip(_typeMappingSource) < end.SimulateDatabaseRoundtrip(_typeMappingSource) && dates.Select(d => d.SimulateDatabaseRoundtrip(_typeMappingSource)).Contains(m.Timeline.SimulateDatabaseRoundtrip(_typeMappingSource))) .Select(m => new Mission() @@ -375,110 +370,201 @@ public override Task DateTimeOffset_Contains_Less_than_Greater_than(bool isAsync } [SupportedServerVersionTheory(ServerVersion.OuterApplySupportKey)] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Correlated_collections_inner_subquery_predicate_references_outer_qsre(bool isAsync) { return base.Correlated_collections_inner_subquery_predicate_references_outer_qsre(isAsync); } [SupportedServerVersionTheory(ServerVersion.OuterApplySupportKey)] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Correlated_collections_inner_subquery_selector_references_outer_qsre(bool isAsync) { return base.Correlated_collections_inner_subquery_selector_references_outer_qsre(isAsync); } [SupportedServerVersionTheory(ServerVersion.OuterApplySupportKey, Skip = "https://bugs.mysql.com/bug.php?id=96946")] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Outer_parameter_in_join_key_inner_and_outer(bool isAsync) { return base.Outer_parameter_in_join_key_inner_and_outer(isAsync); } [SupportedServerVersionTheory(ServerVersion.OuterApplySupportKey, Skip = "https://bugs.mysql.com/bug.php?id=96946")] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Outer_parameter_in_group_join_with_DefaultIfEmpty(bool isAsync) { return base.Outer_parameter_in_group_join_with_DefaultIfEmpty(isAsync); } [SupportedServerVersionTheory(ServerVersion.OuterApplySupportKey, Skip = "https://bugs.mysql.com/bug.php?id=96946")] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Outer_parameter_in_join_key(bool isAsync) { return base.Outer_parameter_in_join_key(isAsync); } [SupportedServerVersionTheory(ServerVersion.OuterApplySupportKey)] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Correlated_collections_nested_inner_subquery_references_outer_qsre_two_levels_up(bool isAsync) { return base.Correlated_collections_nested_inner_subquery_references_outer_qsre_two_levels_up(isAsync); } [SupportedServerVersionTheory(ServerVersion.OuterApplySupportKey)] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Select_subquery_distinct_firstordefault(bool isAsync) { return base.Select_subquery_distinct_firstordefault(isAsync); } [SupportedServerVersionTheory(ServerVersion.OuterApplySupportKey)] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Select_subquery_distinct_singleordefault_boolean1(bool isAsync) { return base.Select_subquery_distinct_singleordefault_boolean1(isAsync); } [SupportedServerVersionTheory(ServerVersion.OuterApplySupportKey)] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Select_subquery_distinct_singleordefault_boolean_empty1(bool isAsync) { return base.Select_subquery_distinct_singleordefault_boolean_empty1(isAsync); } [SupportedServerVersionTheory(ServerVersion.OuterApplySupportKey)] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Select_subquery_distinct_singleordefault_boolean_with_pushdown(bool isAsync) { return base.Select_subquery_distinct_singleordefault_boolean_with_pushdown(isAsync); } [SupportedServerVersionTheory(ServerVersion.OuterApplySupportKey)] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Select_subquery_distinct_singleordefault_boolean_empty_with_pushdown(bool isAsync) { return base.Select_subquery_distinct_singleordefault_boolean_empty_with_pushdown(isAsync); } [SupportedServerVersionTheory(ServerVersion.OuterApplySupportKey)] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Where_subquery_distinct_first_boolean(bool isAsync) { return base.Where_subquery_distinct_first_boolean(isAsync); } [SupportedServerVersionTheory(ServerVersion.OuterApplySupportKey)] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Where_subquery_distinct_singleordefault_boolean1(bool isAsync) { return base.Where_subquery_distinct_singleordefault_boolean1(isAsync); } [SupportedServerVersionTheory(ServerVersion.OuterApplySupportKey)] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Where_subquery_distinct_singleordefault_boolean_with_pushdown(bool isAsync) { return base.Where_subquery_distinct_singleordefault_boolean_with_pushdown(isAsync); } [SupportedServerVersionTheory(ServerVersion.OuterApplySupportKey)] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Correlated_collections_nested_inner_subquery_references_outer_qsre_one_level_up(bool isAsync) { return base.Correlated_collections_nested_inner_subquery_references_outer_qsre_one_level_up(isAsync); } - + + [SupportedServerVersionTheory(ServerVersion.OuterApplySupportKey)] + [MemberData(nameof(IsAsyncData))] + public override Task Project_collection_navigation_nested_with_take_composite_key(bool isAsync) + { + return base.Project_collection_navigation_nested_with_take_composite_key(isAsync); + } + + [SupportedServerVersionTheory(ServerVersion.WindowFunctionsSupportKey)] + [MemberData(nameof(IsAsyncData))] + public override Task Project_entity_and_collection_element(bool isAsync) + { + return base.Project_entity_and_collection_element(isAsync); + } + + [SupportedServerVersionTheory(ServerVersion.WindowFunctionsSupportKey)] + [MemberData(nameof(IsAsyncData))] + public override Task Project_one_value_type_with_client_projection_from_empty_collection(bool isAsync) + { + return base.Project_one_value_type_with_client_projection_from_empty_collection(isAsync); + } + + [SupportedServerVersionTheory(ServerVersion.WindowFunctionsSupportKey)] + [MemberData(nameof(IsAsyncData))] + public override Task Select_subquery_projecting_multiple_constants_inside_anonymous(bool isAsync) + { + return base.Select_subquery_projecting_multiple_constants_inside_anonymous(isAsync); + } + + [SupportedServerVersionTheory(ServerVersion.WindowFunctionsSupportKey)] + [MemberData(nameof(IsAsyncData))] + public override Task Select_subquery_projecting_single_constant_inside_anonymous(bool isAsync) + { + return base.Select_subquery_projecting_single_constant_inside_anonymous(isAsync); + } + + [SupportedServerVersionTheory(ServerVersion.WindowFunctionsSupportKey)] + [MemberData(nameof(IsAsyncData))] + public override Task Select_subquery_projecting_single_constant_null_of_non_mapped_type(bool isAsync) + { + return base.Select_subquery_projecting_single_constant_null_of_non_mapped_type(isAsync); + } + + [SupportedServerVersionTheory(ServerVersion.WindowFunctionsSupportKey)] + [MemberData(nameof(IsAsyncData))] + public override Task Select_subquery_projecting_single_constant_of_non_mapped_type(bool isAsync) + { + return base.Select_subquery_projecting_single_constant_of_non_mapped_type(isAsync); + } + + [SupportedServerVersionTheory("8.0.18-mysql", Skip = "TODO: Pinpoint exact version number! Referencing outer column from WHERE subquery does not work in previous versions. Inverse of #573")] + [MemberData(nameof(IsAsyncData))] + public override Task Where_subquery_distinct_firstordefault_boolean(bool isAsync) + { + return base.Where_subquery_distinct_firstordefault_boolean(isAsync); + } + + [SupportedServerVersionTheory("8.0.18-mysql", Skip = "TODO: Pinpoint exact version number! Referencing outer column from WHERE subquery does not work in previous versions. Inverse of #573")] + [MemberData(nameof(IsAsyncData))] + public override Task Where_subquery_distinct_firstordefault_boolean_with_pushdown(bool isAsync) + { + return base.Where_subquery_distinct_firstordefault_boolean_with_pushdown(isAsync); + } + + [SupportedServerVersionTheory("8.0.18-mysql", Skip = "TODO: Pinpoint exact version number! Referencing outer column from WHERE subquery does not work in previous versions. Inverse of #573")] + [MemberData(nameof(IsAsyncData))] + public override Task Where_subquery_distinct_lastordefault_boolean(bool isAsync) + { + return base.Where_subquery_distinct_lastordefault_boolean(isAsync); + } + + [SupportedServerVersionTheory("8.0.18-mysql", Skip = "TODO: Pinpoint exact version number! Referencing outer column from WHERE subquery does not work in previous versions. Inverse of #573")] + [MemberData(nameof(IsAsyncData))] + public override Task Where_subquery_distinct_last_boolean(bool isAsync) + { + return base.Where_subquery_distinct_last_boolean(isAsync); + } + + [SupportedServerVersionTheory("8.0.18-mysql", Skip = "TODO: Pinpoint exact version number! Referencing outer column from WHERE subquery does not work in previous versions. Inverse of #573")] + [MemberData(nameof(IsAsyncData))] + public override Task Where_subquery_distinct_orderby_firstordefault_boolean(bool isAsync) + { + return base.Where_subquery_distinct_orderby_firstordefault_boolean(isAsync); + } + + [SupportedServerVersionTheory("8.0.18-mysql", Skip = "TODO: Pinpoint exact version number! Referencing outer column from WHERE subquery does not work in previous versions. Inverse of #573")] + [MemberData(nameof(IsAsyncData))] + public override Task Where_subquery_distinct_orderby_firstordefault_boolean_with_pushdown(bool isAsync) + { + return base.Where_subquery_distinct_orderby_firstordefault_boolean_with_pushdown(isAsync); + } + [SupportedServerVersionLessThanTheory("5.6.0", Skip = "https://bugs.mysql.com/bug.php?id=96947")] [MemberData(nameof(IsAsyncData))] public override Task Correlated_collections_basic_projecting_constant(bool isAsync) @@ -493,14 +579,14 @@ public override Task Correlated_collections_basic_projecting_constant_bool(bool return base.Correlated_collections_basic_projecting_constant_bool(isAsync); } - [ConditionalTheory(Skip = "https://github.com/mysql-net/MySqlConnector/pull/707")] + [ConditionalTheory(/*Skip = "https://github.com/mysql-net/MySqlConnector/pull/707"*/)] [MemberData(nameof(IsAsyncData))] public override Task Optional_Navigation_Null_Coalesce_To_Clr_Type(bool isAsync) { return base.Optional_Navigation_Null_Coalesce_To_Clr_Type(isAsync); } - [ConditionalTheory(Skip = "https://github.com/mysql-net/MySqlConnector/pull/707")] + [ConditionalTheory(/*Skip = "https://github.com/mysql-net/MySqlConnector/pull/707"*/)] [MemberData(nameof(IsAsyncData))] public override Task Projecting_nullable_bool_in_conditional_works(bool isAsync) { @@ -521,11 +607,9 @@ public override Task Take_without_orderby_followed_by_orderBy_is_pushed_down2(bo return base.Take_without_orderby_followed_by_orderBy_is_pushed_down2(isAsync); } - public Task AssertQueryScalar(bool isAsync, - Func, IQueryable> query, - bool assertOrder = false) - where TItem : class - => AssertQueryScalar( + protected Task AssertQueryScalar(bool isAsync, + Func> query, + bool assertOrder = false) => AssertQueryScalar( isAsync, query, ms => query(ms).Select(d => d.SimulateDatabaseRoundtrip(_typeMappingSource)), diff --git a/test/EFCore.MySql.FunctionalTests/Query/GroupByQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/GroupByQueryMySqlTest.cs index dc23c14f6..22cb23760 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/GroupByQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/GroupByQueryMySqlTest.cs @@ -1,5 +1,8 @@ -using Microsoft.EntityFrameworkCore.Query; +using System; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; using Xunit.Abstractions; namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query @@ -13,5 +16,17 @@ public GroupByQueryMySqlTest(NorthwindQueryMySqlFixture fix Fixture.TestSqlLoggerFactory.Clear(); //Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); } + + public override Task GroupBy_Property_Select_Count_with_predicate(bool isAsync) + { + return Assert.ThrowsAsync( + () => base.GroupBy_Property_Select_Count_with_predicate(isAsync)); + } + + public override Task GroupBy_Property_Select_LongCount_with_predicate(bool isAsync) + { + return Assert.ThrowsAsync( + () => base.GroupBy_Property_Select_LongCount_with_predicate(isAsync)); + } } } diff --git a/test/EFCore.MySql.FunctionalTests/Query/IncludeAsyncMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/IncludeAsyncMySqlTest.cs index cdc4151e1..501d425fe 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/IncludeAsyncMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/IncludeAsyncMySqlTest.cs @@ -39,7 +39,7 @@ from c2 in context.Set() .Take(1) .ToListAsync(); - Assert.Equal(1, customers.Count); + Assert.Single(customers); Assert.Equal(6, customers.SelectMany(c => c.c1.Orders).Count()); Assert.True(customers.SelectMany(c => c.c1.Orders).All(o => o.Customer != null)); Assert.Equal(7, customers.SelectMany(c => c.c2.Orders).Count()); diff --git a/test/EFCore.MySql.FunctionalTests/Query/IncludeMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/IncludeMySqlTest.cs index e3119c06a..b6f931ee1 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/IncludeMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/IncludeMySqlTest.cs @@ -61,7 +61,7 @@ from c2 in context.Set() .Take(1) .ToList(); - Assert.Equal(1, customers.Count); + Assert.Single(customers); Assert.Equal(6, customers.SelectMany(c => c.c1.Orders).Count()); Assert.True(customers.SelectMany(c => c.c1.Orders).All(o => o.Customer != null)); Assert.Equal(7, customers.SelectMany(c => c.c2.Orders).Count()); diff --git a/test/EFCore.MySql.FunctionalTests/Query/QueryNavigationsMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/QueryNavigationsMySqlTest.cs index ba1371f0c..f632058d6 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/QueryNavigationsMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/QueryNavigationsMySqlTest.cs @@ -18,73 +18,79 @@ public QueryNavigationsMySqlTest(NorthwindQueryMySqlFixture } [ConditionalTheory(Skip = "Issue #573")] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Where_subquery_on_navigation(bool isAsync) { return base.Where_subquery_on_navigation(isAsync); } [ConditionalTheory(Skip = "Issue #573")] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Where_subquery_on_navigation2(bool isAsync) { return base.Where_subquery_on_navigation2(isAsync); } - [ConditionalTheory(Skip = "Issue #573")] - [MemberData("IsAsyncData")] + [ConditionalFact(Skip = "Issue #573")] public override void Navigation_in_subquery_referencing_outer_query_with_client_side_result_operator_and_count() { base.Navigation_in_subquery_referencing_outer_query_with_client_side_result_operator_and_count(); } [SupportedServerVersionTheory(ServerVersion.WindowFunctionsSupportKey)] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Collection_select_nav_prop_first_or_default(bool isAsync) { return base.Collection_select_nav_prop_first_or_default(isAsync); } [SupportedServerVersionTheory(ServerVersion.WindowFunctionsSupportKey)] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Collection_select_nav_prop_first_or_default_then_nav_prop(bool isAsync) { return base.Collection_select_nav_prop_first_or_default_then_nav_prop(isAsync); } [SupportedServerVersionTheory(ServerVersion.WindowFunctionsSupportKey)] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Project_single_entity_value_subquery_works(bool isAsync) { return base.Project_single_entity_value_subquery_works(isAsync); } [SupportedServerVersionTheory(ServerVersion.WindowFunctionsSupportKey)] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Select_collection_FirstOrDefault_project_anonymous_type(bool isAsync) { return base.Select_collection_FirstOrDefault_project_anonymous_type(isAsync); } [SupportedServerVersionTheory(ServerVersion.WindowFunctionsSupportKey)] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Select_collection_FirstOrDefault_project_entity(bool isAsync) { return base.Select_collection_FirstOrDefault_project_entity(isAsync); } [SupportedServerVersionTheory(ServerVersion.WindowFunctionsSupportKey)] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Skip_Select_Navigation(bool isAsync) { return base.Skip_Select_Navigation(isAsync); } [SupportedServerVersionTheory(ServerVersion.WindowFunctionsSupportKey)] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Take_Select_Navigation(bool isAsync) { return base.Take_Select_Navigation(isAsync); } + + [SupportedServerVersionTheory(ServerVersion.WindowFunctionsSupportKey)] + [MemberData(nameof(IsAsyncData))] + public override Task Select_collection_FirstOrDefault_project_anonymous_type_client_eval(bool isAsync) + { + return base.Select_collection_FirstOrDefault_project_anonymous_type_client_eval(isAsync); + } } } diff --git a/test/EFCore.MySql.FunctionalTests/Query/QueryNoClientEvalMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/QueryNoClientEvalMySqlTest.cs index 58cfce72f..b1875af9c 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/QueryNoClientEvalMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/QueryNoClientEvalMySqlTest.cs @@ -34,7 +34,7 @@ public override void Throws_when_from_sql_composed() using (var context = CreateContext()) { Assert.Equal( - CoreStrings.TranslationFailed("Where( source: FromSqlOnQueryable( source: DbSet, sql: \"select * from `Customers`\", parameters: (Unhandled parameter: __p_0)), predicate: (c) => c.IsLondon)"), + CoreStrings.TranslationFailed(@"DbSet .FromSqlOnQueryable( source: ""select * from `Customers`"", sql: __p_0) .Where(c => c.IsLondon)"), RemoveNewLines(Assert.Throws( () => context.Customers .FromSqlRaw(NormalizeDelimetersInRawString("select * from [Customers]")) @@ -47,6 +47,6 @@ private string RemoveNewLines(string message) => message.Replace("\n", "").Replace("\r", ""); private string NormalizeDelimetersInRawString(string sql) - => Fixture.TestStore.NormalizeDelimetersInRawString(sql); + => Fixture.TestStore.NormalizeDelimitersInRawString(sql); } } diff --git a/test/EFCore.MySql.FunctionalTests/Query/SimpleQueryMySqlTest.MySql.cs b/test/EFCore.MySql.FunctionalTests/Query/SimpleQueryMySqlTest.MySql.cs index 85a789c6b..101acd161 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/SimpleQueryMySqlTest.MySql.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/SimpleQueryMySqlTest.MySql.cs @@ -14,75 +14,61 @@ namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query public partial class SimpleQueryMySqlTest : SimpleQueryTestBase> { [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task PadLeft_without_second_arg(bool isAsync) { - await AssertSingleResult(isAsync, - customer => customer.Where(r => r.CustomerID.PadLeft(2) == "AL").Count(), - customer => customer.Where(r => r.CustomerID.PadLeft(2) == "AL").CountAsync(), - asserter: (_, a) => - { - var len = (int)a; - Assert.Equal(len, 1); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(r => r.CustomerID.PadLeft(8) == " ALFKI"), + entryCount: 1); + + AssertSql( + @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE LPAD(`c`.`CustomerID`, 2, ' ') = 'AL'"); - } - ); +WHERE LPAD(`c`.`CustomerID`, 8, ' ') = ' ALFKI'"); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task PadLeft_with_second_arg(bool isAsync) { - await AssertSingleResult(isAsync, - customer => customer.Where(r => r.CustomerID.PadLeft(3, 'x') == "AL").Count(), - customer => customer.Where(r => r.CustomerID.PadLeft(3, 'x') == "AL").CountAsync(), - asserter: (_, a) => - { - var len = (int)a; - Assert.Equal(len, 0); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(r => r.CustomerID.PadLeft(8, 'x') == "xxxALFKI"), + entryCount: 1); + + AssertSql( + @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE LPAD(`c`.`CustomerID`, 3, 'x') = 'AL'"); - } - ); +WHERE LPAD(`c`.`CustomerID`, 8, 'x') = 'xxxALFKI'"); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task PadRight_without_second_arg(bool isAsync) { - await AssertSingleResult(isAsync, - customer => customer.Where(r => r.CustomerID.PadRight(3) == "AL").Count(), - customer => customer.Where(r => r.CustomerID.PadRight(3) == "AL").CountAsync(), - asserter: (_, a) => - { - var len = (int)a; - Assert.Equal(len, 0); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(r => r.CustomerID.PadRight(8) == "ALFKI "), + entryCount: 1); + + AssertSql(@"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE RPAD(`c`.`CustomerID`, 3, ' ') = 'AL'"); - } - ); +WHERE RPAD(`c`.`CustomerID`, 8, ' ') = 'ALFKI '"); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task PadRight_with_second_arg(bool isAsync) { - await AssertSingleResult(isAsync, - customer => customer.Where(r => r.CustomerID.PadRight(4, 'c') == "AL").Count(), - customer => customer.Where(r => r.CustomerID.PadRight(4, 'c') == "AL").CountAsync(), - asserter: (_, a) => - { - var len = (int)a; - Assert.Equal(len, 0); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(r => r.CustomerID.PadRight(8, 'c') == "ALFKIccc"), + entryCount: 1); + + AssertSql(@"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE RPAD(`c`.`CustomerID`, 4, 'c') = 'AL'"); - } - ); +WHERE RPAD(`c`.`CustomerID`, 8, 'c') = 'ALFKIccc'"); } [ConditionalTheory] @@ -100,144 +86,109 @@ await AssertSingleResult(isAsync, [InlineData(StringComparison.InvariantCulture, 0, true)] public async Task StringEquals_with_comparison_parameter(StringComparison comparison, int expected, bool isAsync) { - await AssertSingleResult(isAsync, - customer => customer.Where(c => c.CustomerID.Equals("anton", comparison)).Count(), - customer => customer.Where(c => c.CustomerID.Equals("anton", comparison)).CountAsync(), - asserter: (_, a) => - { - Assert.Equal(expected, (int)a); - // When the comparison parameter is not a constant, we have to use a case - // statement - AssertSql( - $@"@__comparison_0='{comparison:D}' - -SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.Equals("anton", comparison)), + entryCount: expected); + + // When the comparison parameter is not a constant, we have to use a case + // statement + AssertSql( + $@"@__comparison_0='{comparison:D}' + +SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE CASE WHEN @__comparison_0 IN (4, 0, 2) THEN `c`.`CustomerID` = CONVERT('anton' USING utf8mb4) COLLATE utf8mb4_bin - ELSE LCASE(`c`.`CustomerID`) = CONVERT(LCASE('anton') USING utf8mb4) COLLATE utf8mb4_bin + ELSE ((LCASE(`c`.`CustomerID`) = CONVERT(LCASE('anton') USING utf8mb4) COLLATE utf8mb4_bin) AND (LCASE(`c`.`CustomerID`) IS NOT NULL AND CONVERT(LCASE('anton') USING utf8mb4) COLLATE utf8mb4_bin IS NOT NULL)) OR (LCASE(`c`.`CustomerID`) IS NULL AND CONVERT(LCASE('anton') USING utf8mb4) COLLATE utf8mb4_bin IS NULL) END"); - }); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringEquals_ordinal(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.Equals("anton", StringComparison.Ordinal)) - .Count(), - customer => - customer.Where(c => c.CustomerID.Equals("anton", StringComparison.Ordinal)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(0, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.Equals("anton", StringComparison.Ordinal)), + entryCount: 0); + + AssertSql(@"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE `c`.`CustomerID` = CONVERT('anton' USING utf8mb4) COLLATE utf8mb4_bin"); - }); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringEquals_invariant(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.Equals("anton", StringComparison.CurrentCulture)) - .Count(), - customer => - customer.Where(c => c.CustomerID.Equals("anton", StringComparison.CurrentCulture)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(0, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.Equals("anton", StringComparison.CurrentCulture)), + entryCount: 0); + + AssertSql(@"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE `c`.`CustomerID` = CONVERT('anton' USING utf8mb4) COLLATE utf8mb4_bin"); - }); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringEquals_current(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.Equals("anton", StringComparison.InvariantCulture)) - .Count(), - customer => - customer.Where(c => c.CustomerID.Equals("anton", StringComparison.InvariantCulture)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(0, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.Equals("anton", StringComparison.InvariantCulture)), + entryCount: 0); + + AssertSql(@"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE `c`.`CustomerID` = CONVERT('anton' USING utf8mb4) COLLATE utf8mb4_bin"); - }); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringEquals_ordinal_ignore_case(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.Equals("anton", StringComparison.OrdinalIgnoreCase)) - .Count(), - customer => - customer.Where(c => c.CustomerID.Equals("anton", StringComparison.OrdinalIgnoreCase)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(1, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.Equals("anton", StringComparison.OrdinalIgnoreCase)), + entryCount: 1); + + AssertSql( + @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE LCASE(`c`.`CustomerID`) = CONVERT(LCASE('anton') USING utf8mb4) COLLATE utf8mb4_bin"); - }); +WHERE (LCASE(`c`.`CustomerID`) = CONVERT(LCASE('anton') USING utf8mb4) COLLATE utf8mb4_bin) OR (LCASE(`c`.`CustomerID`) IS NULL AND CONVERT(LCASE('anton') USING utf8mb4) COLLATE utf8mb4_bin IS NULL)"); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringEquals_current_ignore_case(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.Equals("anton", StringComparison.CurrentCultureIgnoreCase)) - .Count(), - customer => - customer.Where(c => c.CustomerID.Equals("anton", StringComparison.CurrentCultureIgnoreCase)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(1, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.Equals("anton", StringComparison.CurrentCultureIgnoreCase)), + entryCount: 1); + + AssertSql( + @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE LCASE(`c`.`CustomerID`) = CONVERT(LCASE('anton') USING utf8mb4) COLLATE utf8mb4_bin"); - }); +WHERE (LCASE(`c`.`CustomerID`) = CONVERT(LCASE('anton') USING utf8mb4) COLLATE utf8mb4_bin) OR (LCASE(`c`.`CustomerID`) IS NULL AND CONVERT(LCASE('anton') USING utf8mb4) COLLATE utf8mb4_bin IS NULL)"); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringEquals_invariant_ignore_case(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.Equals("anton", StringComparison.InvariantCultureIgnoreCase)) - .Count(), - customer => - customer.Where(c => c.CustomerID.Equals("anton", StringComparison.InvariantCultureIgnoreCase)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(1, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.Equals("anton", StringComparison.InvariantCultureIgnoreCase)), + entryCount: 1); + + AssertSql( + @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE LCASE(`c`.`CustomerID`) = CONVERT(LCASE('anton') USING utf8mb4) COLLATE utf8mb4_bin"); - }); +WHERE (LCASE(`c`.`CustomerID`) = CONVERT(LCASE('anton') USING utf8mb4) COLLATE utf8mb4_bin) OR (LCASE(`c`.`CustomerID`) IS NULL AND CONVERT(LCASE('anton') USING utf8mb4) COLLATE utf8mb4_bin IS NULL)"); } [ConditionalTheory] @@ -255,144 +206,109 @@ await AssertSingleResult(isAsync, [InlineData(StringComparison.InvariantCulture, 0, true)] public async Task StaticStringEquals_with_comparison(StringComparison comparison, int expected, bool isAsync) { - await AssertSingleResult(isAsync, - customer => customer.Where(c => string.Equals(c.CustomerID, "anton", comparison)).Count(), - customer => customer.Where(c => string.Equals(c.CustomerID, "anton", comparison)).CountAsync(), - asserter: (_, a) => - { - Assert.Equal(expected, (int)a); - // When the comparison parameter is not a constant, we have to use a case - // statement - AssertSql( - $@"@__comparison_0='{comparison:D}' - -SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => string.Equals(c.CustomerID, "anton", comparison)), + entryCount: expected); + + // When the comparison parameter is not a constant, we have to use a case + // statement + AssertSql( + $@"@__comparison_0='{comparison:D}' + +SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE CASE WHEN @__comparison_0 IN (4, 0, 2) THEN `c`.`CustomerID` = CONVERT('anton' USING utf8mb4) COLLATE utf8mb4_bin - ELSE LCASE(`c`.`CustomerID`) = CONVERT(LCASE('anton') USING utf8mb4) COLLATE utf8mb4_bin + ELSE ((LCASE(`c`.`CustomerID`) = CONVERT(LCASE('anton') USING utf8mb4) COLLATE utf8mb4_bin) AND (LCASE(`c`.`CustomerID`) IS NOT NULL AND CONVERT(LCASE('anton') USING utf8mb4) COLLATE utf8mb4_bin IS NOT NULL)) OR (LCASE(`c`.`CustomerID`) IS NULL AND CONVERT(LCASE('anton') USING utf8mb4) COLLATE utf8mb4_bin IS NULL) END"); - }); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StaticStringEquals_ordinal(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => string.Equals(c.CustomerID, "anton", StringComparison.Ordinal)) - .Count(), - customer => - customer.Where(c => string.Equals(c.CustomerID, "anton", StringComparison.Ordinal)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(0, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => string.Equals(c.CustomerID, "anton", StringComparison.Ordinal)), + entryCount: 0); + + AssertSql(@"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE `c`.`CustomerID` = CONVERT('anton' USING utf8mb4) COLLATE utf8mb4_bin"); - }); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StaticStringEquals_invariant(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => string.Equals(c.CustomerID, "anton", StringComparison.CurrentCulture)) - .Count(), - customer => - customer.Where(c => string.Equals(c.CustomerID, "anton", StringComparison.CurrentCulture)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(0, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => string.Equals(c.CustomerID, "anton", StringComparison.CurrentCulture)), + entryCount: 0); + + AssertSql(@"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE `c`.`CustomerID` = CONVERT('anton' USING utf8mb4) COLLATE utf8mb4_bin"); - }); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StaticStringEquals_current(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => string.Equals(c.CustomerID, "anton", StringComparison.InvariantCulture)) - .Count(), - customer => - customer.Where(c => string.Equals(c.CustomerID, "anton", StringComparison.InvariantCulture)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(0, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => string.Equals(c.CustomerID, "anton", StringComparison.InvariantCulture)), + entryCount: 0); + + AssertSql(@"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE `c`.`CustomerID` = CONVERT('anton' USING utf8mb4) COLLATE utf8mb4_bin"); - }); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StaticStringEquals_ordinal_ignore_case(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => string.Equals(c.CustomerID, "anton", StringComparison.OrdinalIgnoreCase)) - .Count(), - customer => - customer.Where(c => string.Equals(c.CustomerID, "anton", StringComparison.OrdinalIgnoreCase)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(1, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => string.Equals(c.CustomerID, "anton", StringComparison.OrdinalIgnoreCase)), + entryCount: 1); + + AssertSql( + @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE LCASE(`c`.`CustomerID`) = CONVERT(LCASE('anton') USING utf8mb4) COLLATE utf8mb4_bin"); - }); +WHERE (LCASE(`c`.`CustomerID`) = CONVERT(LCASE('anton') USING utf8mb4) COLLATE utf8mb4_bin) OR (LCASE(`c`.`CustomerID`) IS NULL AND CONVERT(LCASE('anton') USING utf8mb4) COLLATE utf8mb4_bin IS NULL)"); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StaticStringEquals_current_ignore_case(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => string.Equals(c.CustomerID, "anton", StringComparison.CurrentCultureIgnoreCase)) - .Count(), - customer => - customer.Where(c => string.Equals(c.CustomerID, "anton", StringComparison.CurrentCultureIgnoreCase)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(1, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => string.Equals(c.CustomerID, "anton", StringComparison.CurrentCultureIgnoreCase)), + entryCount: 1); + + AssertSql( + @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE LCASE(`c`.`CustomerID`) = CONVERT(LCASE('anton') USING utf8mb4) COLLATE utf8mb4_bin"); - }); +WHERE (LCASE(`c`.`CustomerID`) = CONVERT(LCASE('anton') USING utf8mb4) COLLATE utf8mb4_bin) OR (LCASE(`c`.`CustomerID`) IS NULL AND CONVERT(LCASE('anton') USING utf8mb4) COLLATE utf8mb4_bin IS NULL)"); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StaticStringEquals_invariant_ignore_case(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => string.Equals(c.CustomerID, "anton", StringComparison.InvariantCultureIgnoreCase)) - .Count(), - customer => - customer.Where(c => string.Equals(c.CustomerID, "anton", StringComparison.InvariantCultureIgnoreCase)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(1, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => string.Equals(c.CustomerID, "anton", StringComparison.InvariantCultureIgnoreCase)), + entryCount: 1); + + AssertSql( + @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE LCASE(`c`.`CustomerID`) = CONVERT(LCASE('anton') USING utf8mb4) COLLATE utf8mb4_bin"); - }); +WHERE (LCASE(`c`.`CustomerID`) = CONVERT(LCASE('anton') USING utf8mb4) COLLATE utf8mb4_bin) OR (LCASE(`c`.`CustomerID`) IS NULL AND CONVERT(LCASE('anton') USING utf8mb4) COLLATE utf8mb4_bin IS NULL)"); } [ConditionalTheory] @@ -410,144 +326,106 @@ await AssertSingleResult(isAsync, [InlineData(StringComparison.InvariantCulture, 0, true)] public async Task StringContains_with_comparison(StringComparison comparison, int expected, bool isAsync) { - await AssertSingleResult(isAsync, - customer => customer.Where(c => c.CustomerID.Contains("nto", comparison)).Count(), - customer => customer.Where(c => c.CustomerID.Contains("nto", comparison)).CountAsync(), - asserter: (_, a) => - { - Assert.Equal(expected, (int)a); - // When the comparison parameter is not a constant, we have to use a case - // statement - AssertSql( - $@"@__comparison_0='{comparison:D}' - -SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.Contains("nto", comparison)), + entryCount: expected); + + // When the comparison parameter is not a constant, we have to use a case + // statement + AssertSql( + $@"@__comparison_0='{comparison:D}' + +SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE CASE WHEN @__comparison_0 IN (4, 0, 2) THEN LOCATE(CONVERT('nto' USING utf8mb4) COLLATE utf8mb4_bin, `c`.`CustomerID`) > 0 ELSE LOCATE(CONVERT(LCASE('nto') USING utf8mb4) COLLATE utf8mb4_bin, LCASE(`c`.`CustomerID`)) > 0 END"); - }); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringContains_ordinal(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.Contains("nto", StringComparison.Ordinal)) - .Count(), - customer => - customer.Where(c => c.CustomerID.Contains("nto", StringComparison.Ordinal)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(0, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.Contains("nto", StringComparison.Ordinal)), + entryCount: 0); + + AssertSql(@"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE LOCATE(CONVERT('nto' USING utf8mb4) COLLATE utf8mb4_bin, `c`.`CustomerID`) > 0"); - }); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringContains_invariant(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.Contains("nto", StringComparison.CurrentCulture)) - .Count(), - customer => - customer.Where(c => c.CustomerID.Contains("nto", StringComparison.CurrentCulture)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(0, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.Contains("nto", StringComparison.CurrentCulture)), + entryCount: 0); + + AssertSql(@"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE LOCATE(CONVERT('nto' USING utf8mb4) COLLATE utf8mb4_bin, `c`.`CustomerID`) > 0"); - }); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringContains_current(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.Contains("nto", StringComparison.InvariantCulture)) - .Count(), - customer => - customer.Where(c => c.CustomerID.Contains("nto", StringComparison.InvariantCulture)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(0, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.Contains("nto", StringComparison.InvariantCulture)), + entryCount: 0); + + AssertSql(@"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE LOCATE(CONVERT('nto' USING utf8mb4) COLLATE utf8mb4_bin, `c`.`CustomerID`) > 0"); - }); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringContains_ordinal_ignore_case(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.Contains("nto", StringComparison.OrdinalIgnoreCase)) - .Count(), - customer => - customer.Where(c => c.CustomerID.Contains("nto", StringComparison.OrdinalIgnoreCase)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(1, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.Contains("nto", StringComparison.OrdinalIgnoreCase)), + entryCount: 1); + + AssertSql(@"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE LOCATE(CONVERT(LCASE('nto') USING utf8mb4) COLLATE utf8mb4_bin, LCASE(`c`.`CustomerID`)) > 0"); - }); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringContains_current_ignore_case(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.Contains("nto", StringComparison.CurrentCultureIgnoreCase)) - .Count(), - customer => - customer.Where(c => c.CustomerID.Contains("nto", StringComparison.CurrentCultureIgnoreCase)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(1, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.Contains("nto", StringComparison.CurrentCultureIgnoreCase)), + entryCount: 1); + + AssertSql(@"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE LOCATE(CONVERT(LCASE('nto') USING utf8mb4) COLLATE utf8mb4_bin, LCASE(`c`.`CustomerID`)) > 0"); - }); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringContains_invariant_ignore_case(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.Contains("nto", StringComparison.InvariantCultureIgnoreCase)) - .Count(), - customer => - customer.Where(c => c.CustomerID.Contains("nto", StringComparison.InvariantCultureIgnoreCase)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(1, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.Contains("nto", StringComparison.InvariantCultureIgnoreCase)), + entryCount: 1); + + AssertSql(@"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE LOCATE(CONVERT(LCASE('nto') USING utf8mb4) COLLATE utf8mb4_bin, LCASE(`c`.`CustomerID`)) > 0"); - }); } [ConditionalTheory] @@ -565,150 +443,112 @@ await AssertSingleResult(isAsync, [InlineData(StringComparison.InvariantCulture, 0, true)] public async Task StringStartsWith_with_comparison(StringComparison comparison, int expected, bool isAsync) { - await AssertSingleResult(isAsync, - customer => customer.Where(c => c.CustomerID.StartsWith("anto", comparison)).Count(), - customer => customer.Where(c => c.CustomerID.StartsWith("anto", comparison)).CountAsync(), - asserter: (_, a) => - { - Assert.Equal(expected, (int)a); - // When the comparison parameter is not a constant, we have to use a case - // statement - AssertSql( - $@"@__comparison_0='{comparison:D}' - -SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.StartsWith("anto", comparison)), + entryCount: expected); + + // When the comparison parameter is not a constant, we have to use a case + // statement + AssertSql( + $@"@__comparison_0='{comparison:D}' + +SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE CASE - WHEN @__comparison_0 IN (4, 0, 2) THEN (`c`.`CustomerID` LIKE CONCAT('anto', '%')) AND (LEFT(`c`.`CustomerID`, CHAR_LENGTH(CONVERT('anto' USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT('anto' USING utf8mb4) COLLATE utf8mb4_bin) - ELSE (LCASE(`c`.`CustomerID`) LIKE CONCAT(CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin, '%')) AND (LEFT(LCASE(`c`.`CustomerID`), CHAR_LENGTH(CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin) + WHEN @__comparison_0 IN (4, 0, 2) THEN (`c`.`CustomerID` LIKE CONCAT('anto', '%')) AND ((LEFT(`c`.`CustomerID`, CHAR_LENGTH(CONVERT('anto' USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT('anto' USING utf8mb4) COLLATE utf8mb4_bin) AND LEFT(`c`.`CustomerID`, CHAR_LENGTH(CONVERT('anto' USING utf8mb4) COLLATE utf8mb4_bin)) IS NOT NULL) + ELSE (LCASE(`c`.`CustomerID`) LIKE CONCAT(CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin, '%')) AND (((LEFT(LCASE(`c`.`CustomerID`), CHAR_LENGTH(CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin) AND (LEFT(LCASE(`c`.`CustomerID`), CHAR_LENGTH(CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin)) IS NOT NULL AND CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin IS NOT NULL)) OR (LEFT(LCASE(`c`.`CustomerID`), CHAR_LENGTH(CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin)) IS NULL AND CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin IS NULL)) END"); - }); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringStartsWith_ordinal(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.StartsWith("anto", StringComparison.Ordinal)) - .Count(), - customer => - customer.Where(c => c.CustomerID.StartsWith("anto", StringComparison.Ordinal)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(0, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.StartsWith("anto", StringComparison.Ordinal)), + entryCount: 0); + + AssertSql(@"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE (`c`.`CustomerID` LIKE CONCAT('anto', '%')) AND " + - "(LEFT(`c`.`CustomerID`, CHAR_LENGTH(CONVERT('anto' USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT('anto' USING utf8mb4) COLLATE utf8mb4_bin)"); - }); + "(LEFT(`c`.`CustomerID`, CHAR_LENGTH(CONVERT('anto' USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT('anto' USING utf8mb4) COLLATE utf8mb4_bin)"); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringStartsWith_invariant(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.StartsWith("anto", StringComparison.CurrentCulture)) - .Count(), - customer => - customer.Where(c => c.CustomerID.StartsWith("anto", StringComparison.CurrentCulture)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(0, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.StartsWith("anto", StringComparison.CurrentCulture)), + entryCount: 0); + + AssertSql(@"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE (`c`.`CustomerID` LIKE CONCAT('anto', '%')) AND " + - "(LEFT(`c`.`CustomerID`, CHAR_LENGTH(CONVERT('anto' USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT('anto' USING utf8mb4) COLLATE utf8mb4_bin)"); - }); + "(LEFT(`c`.`CustomerID`, CHAR_LENGTH(CONVERT('anto' USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT('anto' USING utf8mb4) COLLATE utf8mb4_bin)"); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringStartsWith_current(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.StartsWith("anto", StringComparison.InvariantCulture)) - .Count(), - customer => - customer.Where(c => c.CustomerID.StartsWith("anto", StringComparison.InvariantCulture)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(0, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.StartsWith("anto", StringComparison.InvariantCulture)), + entryCount: 0); + + AssertSql(@"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE (`c`.`CustomerID` LIKE CONCAT('anto', '%')) AND " + - "(LEFT(`c`.`CustomerID`, CHAR_LENGTH(CONVERT('anto' USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT('anto' USING utf8mb4) COLLATE utf8mb4_bin)"); - }); + "(LEFT(`c`.`CustomerID`, CHAR_LENGTH(CONVERT('anto' USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT('anto' USING utf8mb4) COLLATE utf8mb4_bin)"); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringStartsWith_ordinal_ignore_case(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.StartsWith("anto", StringComparison.OrdinalIgnoreCase)) - .Count(), - customer => - customer.Where(c => c.CustomerID.StartsWith("anto", StringComparison.OrdinalIgnoreCase)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(1, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.StartsWith("anto", StringComparison.OrdinalIgnoreCase)), + entryCount: 1); + + AssertSql( + @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE (LCASE(`c`.`CustomerID`) LIKE CONCAT(CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin, '%')) AND " + - "(LEFT(LCASE(`c`.`CustomerID`), CHAR_LENGTH(CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin)"); - }); +WHERE (LCASE(`c`.`CustomerID`) LIKE CONCAT(CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin, '%')) AND ((LEFT(LCASE(`c`.`CustomerID`), CHAR_LENGTH(CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin) OR (LEFT(LCASE(`c`.`CustomerID`), CHAR_LENGTH(CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin)) IS NULL AND CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin IS NULL))"); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringStartsWith_current_ignore_case(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.StartsWith("anto", StringComparison.CurrentCultureIgnoreCase)) - .Count(), - customer => - customer.Where(c => c.CustomerID.StartsWith("anto", StringComparison.CurrentCultureIgnoreCase)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(1, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.StartsWith("anto", StringComparison.CurrentCultureIgnoreCase)), + entryCount: 1); + + AssertSql( + @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE (LCASE(`c`.`CustomerID`) LIKE CONCAT(CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin, '%')) AND " + - "(LEFT(LCASE(`c`.`CustomerID`), CHAR_LENGTH(CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin)"); - }); +WHERE (LCASE(`c`.`CustomerID`) LIKE CONCAT(CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin, '%')) AND ((LEFT(LCASE(`c`.`CustomerID`), CHAR_LENGTH(CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin) OR (LEFT(LCASE(`c`.`CustomerID`), CHAR_LENGTH(CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin)) IS NULL AND CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin IS NULL))"); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringStartsWith_invariant_ignore_case(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.StartsWith("anto", StringComparison.InvariantCultureIgnoreCase)) - .Count(), - customer => - customer.Where(c => c.CustomerID.StartsWith("anto", StringComparison.InvariantCultureIgnoreCase)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(1, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.StartsWith("anto", StringComparison.InvariantCultureIgnoreCase)), + entryCount: 1); + + AssertSql( + @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE (LCASE(`c`.`CustomerID`) LIKE CONCAT(CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin, '%')) AND " + - "(LEFT(LCASE(`c`.`CustomerID`), CHAR_LENGTH(CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin)"); - }); +WHERE (LCASE(`c`.`CustomerID`) LIKE CONCAT(CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin, '%')) AND ((LEFT(LCASE(`c`.`CustomerID`), CHAR_LENGTH(CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin) OR (LEFT(LCASE(`c`.`CustomerID`), CHAR_LENGTH(CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin)) IS NULL AND CONVERT(LCASE('anto') USING utf8mb4) COLLATE utf8mb4_bin IS NULL))"); } [ConditionalTheory] @@ -726,144 +566,107 @@ await AssertSingleResult(isAsync, [InlineData(StringComparison.InvariantCulture, 0, true)] public async Task StringEndsWith_with_comparison(StringComparison comparison, int expected, bool isAsync) { - await AssertSingleResult(isAsync, - customer => customer.Where(c => c.CustomerID.EndsWith("nton", comparison)).Count(), - customer => customer.Where(c => c.CustomerID.EndsWith("nton", comparison)).CountAsync(), - asserter: (_, a) => - { - Assert.Equal(expected, (int)a); - // When the comparison parameter is not a constant, we have to use a case - // statement - AssertSql( + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.EndsWith("nton", comparison)), + entryCount: expected); + + AssertSql( $@"@__comparison_0='{comparison:D}' -SELECT COUNT(*) +SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE CASE - WHEN @__comparison_0 IN (4, 0, 2) THEN RIGHT(`c`.`CustomerID`, CHAR_LENGTH(CONVERT('nton' USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT('nton' USING utf8mb4) COLLATE utf8mb4_bin - ELSE RIGHT(LCASE(`c`.`CustomerID`), CHAR_LENGTH(CONVERT(LCASE('nton') USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT(LCASE('nton') USING utf8mb4) COLLATE utf8mb4_bin + WHEN @__comparison_0 IN (4, 0, 2) THEN (RIGHT(`c`.`CustomerID`, CHAR_LENGTH(CONVERT('nton' USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT('nton' USING utf8mb4) COLLATE utf8mb4_bin) AND RIGHT(`c`.`CustomerID`, CHAR_LENGTH(CONVERT('nton' USING utf8mb4) COLLATE utf8mb4_bin)) IS NOT NULL + ELSE ((RIGHT(LCASE(`c`.`CustomerID`), CHAR_LENGTH(CONVERT(LCASE('nton') USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT(LCASE('nton') USING utf8mb4) COLLATE utf8mb4_bin) AND (RIGHT(LCASE(`c`.`CustomerID`), CHAR_LENGTH(CONVERT(LCASE('nton') USING utf8mb4) COLLATE utf8mb4_bin)) IS NOT NULL AND CONVERT(LCASE('nton') USING utf8mb4) COLLATE utf8mb4_bin IS NOT NULL)) OR (RIGHT(LCASE(`c`.`CustomerID`), CHAR_LENGTH(CONVERT(LCASE('nton') USING utf8mb4) COLLATE utf8mb4_bin)) IS NULL AND CONVERT(LCASE('nton') USING utf8mb4) COLLATE utf8mb4_bin IS NULL) END"); - }); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringEndsWith_ordinal(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.EndsWith("nton", StringComparison.Ordinal)) - .Count(), - customer => - customer.Where(c => c.CustomerID.EndsWith("nton", StringComparison.Ordinal)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(0, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.EndsWith("nton", StringComparison.Ordinal)), + entryCount: 0); + + AssertSql(@"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE RIGHT(`c`.`CustomerID`, CHAR_LENGTH(CONVERT('nton' USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT('nton' USING utf8mb4) COLLATE utf8mb4_bin"); - }); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringEndsWith_invariant(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.EndsWith("nton", StringComparison.CurrentCulture)) - .Count(), - customer => - customer.Where(c => c.CustomerID.EndsWith("nton", StringComparison.CurrentCulture)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(0, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.EndsWith("nton", StringComparison.CurrentCulture)), + entryCount: 0); + + AssertSql(@"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE RIGHT(`c`.`CustomerID`, CHAR_LENGTH(CONVERT('nton' USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT('nton' USING utf8mb4) COLLATE utf8mb4_bin"); - }); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringEndsWith_current(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.EndsWith("nton", StringComparison.InvariantCulture)) - .Count(), - customer => - customer.Where(c => c.CustomerID.EndsWith("nton", StringComparison.InvariantCulture)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(0, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.EndsWith("nton", StringComparison.InvariantCulture)), + entryCount: 0); + + AssertSql(@"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE RIGHT(`c`.`CustomerID`, CHAR_LENGTH(CONVERT('nton' USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT('nton' USING utf8mb4) COLLATE utf8mb4_bin"); - }); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringEndsWith_ordinal_ignore_case(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.EndsWith("nton", StringComparison.OrdinalIgnoreCase)) - .Count(), - customer => - customer.Where(c => c.CustomerID.EndsWith("nton", StringComparison.OrdinalIgnoreCase)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(1, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.EndsWith("nton", StringComparison.OrdinalIgnoreCase)), + entryCount: 1); + + AssertSql( + @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE RIGHT(LCASE(`c`.`CustomerID`), CHAR_LENGTH(CONVERT(LCASE('nton') USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT(LCASE('nton') USING utf8mb4) COLLATE utf8mb4_bin"); - }); +WHERE (RIGHT(LCASE(`c`.`CustomerID`), CHAR_LENGTH(CONVERT(LCASE('nton') USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT(LCASE('nton') USING utf8mb4) COLLATE utf8mb4_bin) OR (RIGHT(LCASE(`c`.`CustomerID`), CHAR_LENGTH(CONVERT(LCASE('nton') USING utf8mb4) COLLATE utf8mb4_bin)) IS NULL AND CONVERT(LCASE('nton') USING utf8mb4) COLLATE utf8mb4_bin IS NULL)"); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringEndsWith_current_ignore_case(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.EndsWith("nton", StringComparison.CurrentCultureIgnoreCase)) - .Count(), - customer => - customer.Where(c => c.CustomerID.EndsWith("nton", StringComparison.CurrentCultureIgnoreCase)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(1, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.EndsWith("nton", StringComparison.CurrentCultureIgnoreCase)), + entryCount: 1); + + AssertSql( + @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE RIGHT(LCASE(`c`.`CustomerID`), CHAR_LENGTH(CONVERT(LCASE('nton') USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT(LCASE('nton') USING utf8mb4) COLLATE utf8mb4_bin"); - }); +WHERE (RIGHT(LCASE(`c`.`CustomerID`), CHAR_LENGTH(CONVERT(LCASE('nton') USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT(LCASE('nton') USING utf8mb4) COLLATE utf8mb4_bin) OR (RIGHT(LCASE(`c`.`CustomerID`), CHAR_LENGTH(CONVERT(LCASE('nton') USING utf8mb4) COLLATE utf8mb4_bin)) IS NULL AND CONVERT(LCASE('nton') USING utf8mb4) COLLATE utf8mb4_bin IS NULL)"); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringEndsWith_invariant_ignore_case(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.EndsWith("nton", StringComparison.InvariantCultureIgnoreCase)) - .Count(), - customer => - customer.Where(c => c.CustomerID.EndsWith("nton", StringComparison.InvariantCultureIgnoreCase)) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(1, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.EndsWith("nton", StringComparison.InvariantCultureIgnoreCase)), + entryCount: 1); + + AssertSql( + @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE RIGHT(LCASE(`c`.`CustomerID`), CHAR_LENGTH(CONVERT(LCASE('nton') USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT(LCASE('nton') USING utf8mb4) COLLATE utf8mb4_bin"); - }); +WHERE (RIGHT(LCASE(`c`.`CustomerID`), CHAR_LENGTH(CONVERT(LCASE('nton') USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT(LCASE('nton') USING utf8mb4) COLLATE utf8mb4_bin) OR (RIGHT(LCASE(`c`.`CustomerID`), CHAR_LENGTH(CONVERT(LCASE('nton') USING utf8mb4) COLLATE utf8mb4_bin)) IS NULL AND CONVERT(LCASE('nton') USING utf8mb4) COLLATE utf8mb4_bin IS NULL)"); } [ConditionalTheory] @@ -881,161 +684,123 @@ await AssertSingleResult(isAsync, [InlineData(StringComparison.InvariantCulture, 0, true)] public async Task StringIndexOf_with_comparison(StringComparison comparison, int expected, bool isAsync) { - await AssertSingleResult(isAsync, - customer => customer.Where(c => c.CustomerID.IndexOf("nt", comparison) == 1).Count(), - customer => customer.Where(c => c.CustomerID.IndexOf("nt", comparison) == 1).CountAsync(), - asserter: (_, a) => - { - Assert.Equal(expected, (int)a); - // When the comparison parameter is not a constant, we have to use a case - // statement - AssertSql($"@__comparison_0='{comparison:D}'" + @" - -SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.IndexOf("nt", comparison) == 1), + entryCount: expected); + + // When the comparison parameter is not a constant, we have to use a case + // statement + AssertSql($"@__comparison_0='{comparison:D}'" + @" + +SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE CASE WHEN @__comparison_0 IN (4, 0, 2) THEN LOCATE(CONVERT('nt' USING utf8mb4) COLLATE utf8mb4_bin, `c`.`CustomerID`) - 1 ELSE LOCATE(CONVERT(LCASE('nt') USING utf8mb4) COLLATE utf8mb4_bin, LCASE(`c`.`CustomerID`)) - 1 END = 1"); - }); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringIndexOf_ordinal(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.IndexOf("nt", StringComparison.Ordinal) == 1) - .Count(), - customer => - customer.Where(c => c.CustomerID.IndexOf("nt", StringComparison.Ordinal) == 1) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(0, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.IndexOf("nt", StringComparison.Ordinal) == 1), + entryCount: 0); + + AssertSql(@"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE (LOCATE(CONVERT('nt' USING utf8mb4) COLLATE utf8mb4_bin, `c`.`CustomerID`) - 1) = 1"); - }); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringIndexOf_invariant(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.IndexOf("nt", StringComparison.CurrentCulture) == 1) - .Count(), - customer => - customer.Where(c => c.CustomerID.IndexOf("nt", StringComparison.CurrentCulture) == 1) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(0, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.IndexOf("nt", StringComparison.CurrentCulture) == 1), + entryCount: 0); + + AssertSql(@"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE (LOCATE(CONVERT('nt' USING utf8mb4) COLLATE utf8mb4_bin, `c`.`CustomerID`) - 1) = 1"); - }); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringIndexOf_current(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.IndexOf("nt", StringComparison.InvariantCulture) == 1) - .Count(), - customer => - customer.Where(c => c.CustomerID.IndexOf("nt", StringComparison.InvariantCulture) == 1) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(0, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.IndexOf("nt", StringComparison.InvariantCulture) == 1), + entryCount: 0); + + AssertSql(@"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE (LOCATE(CONVERT('nt' USING utf8mb4) COLLATE utf8mb4_bin, `c`.`CustomerID`) - 1) = 1"); - }); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringIndexOf_ordinal_ignore_case(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.IndexOf("nt", StringComparison.OrdinalIgnoreCase) == 1) - .Count(), - customer => - customer.Where(c => c.CustomerID.IndexOf("nt", StringComparison.OrdinalIgnoreCase) == 1) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(1, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.IndexOf("nt", StringComparison.OrdinalIgnoreCase) == 1), + entryCount: 1); + + AssertSql(@"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE (LOCATE(CONVERT(LCASE('nt') USING utf8mb4) COLLATE utf8mb4_bin, LCASE(`c`.`CustomerID`)) - 1) = 1"); - }); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringIndexOf_current_ignore_case(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.IndexOf("nt", StringComparison.CurrentCultureIgnoreCase) == 1) - .Count(), - customer => - customer.Where(c => c.CustomerID.IndexOf("nt", StringComparison.CurrentCultureIgnoreCase) == 1) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(1, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.IndexOf("nt", StringComparison.CurrentCultureIgnoreCase) == 1), + entryCount: 1); + + AssertSql(@"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE (LOCATE(CONVERT(LCASE('nt') USING utf8mb4) COLLATE utf8mb4_bin, LCASE(`c`.`CustomerID`)) - 1) = 1"); - }); } [ConditionalTheory] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public async Task StringIndexOf_invariant_ignore_case(bool isAsync) { - await AssertSingleResult(isAsync, - customer => - customer.Where(c => c.CustomerID.IndexOf("nt", StringComparison.InvariantCultureIgnoreCase) == 1) - .Count(), - customer => - customer.Where(c => c.CustomerID.IndexOf("nt", StringComparison.InvariantCultureIgnoreCase) == 1) - .CountAsync(), - asserter: (_, a) => - { - Assert.Equal(1, (int)a); - AssertSql(@"SELECT COUNT(*) + await AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.CustomerID.IndexOf("nt", StringComparison.InvariantCultureIgnoreCase) == 1), + entryCount: 1); + + AssertSql(@"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` WHERE (LOCATE(CONVERT(LCASE('nt') USING utf8mb4) COLLATE utf8mb4_bin, LCASE(`c`.`CustomerID`)) - 1) = 1"); - }); } [SupportedServerVersionLessThanTheory(ServerVersion.CrossApplySupportKey)] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public virtual Task CrossApply_not_supported_throws(bool isAsync) { return Assert.ThrowsAsync(() => base.SelectMany_correlated_with_outer_1(isAsync)); } [SupportedServerVersionLessThanTheory(ServerVersion.OuterApplySupportKey)] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public virtual Task OuterApply_not_supported_throws(bool isAsync) { return Assert.ThrowsAsync(() => base.SelectMany_correlated_with_outer_3(isAsync)); } - + [SupportedServerVersionLessThanTheory(ServerVersion.WindowFunctionsSupportKey)] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public Task RowNumberOverPartitionBy_not_supported_throws(bool isAsync) { return Assert.ThrowsAsync(() => base.SelectMany_Joined_Take(isAsync)); diff --git a/test/EFCore.MySql.FunctionalTests/Query/SimpleQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/SimpleQueryMySqlTest.cs index 2d74209c0..b39c31bb4 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/SimpleQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/SimpleQueryMySqlTest.cs @@ -1,7 +1,11 @@ using System; +using System.Linq; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.Query.SqlExpressions; +using Microsoft.EntityFrameworkCore.TestModels.Northwind; using Microsoft.EntityFrameworkCore.TestUtilities; +using MySql.Data.MySqlClient; using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities.Attributes; using Pomelo.EntityFrameworkCore.MySql.Storage; using Xunit; @@ -19,6 +23,8 @@ public SimpleQueryMySqlTest(NorthwindQueryMySqlFixture fixt Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Take_Skip(bool isAsync) { await base.Take_Skip(isAsync); @@ -38,6 +44,8 @@ ORDER BY `t`.`ContactName` LIMIT 18446744073709551610 OFFSET @__p_1"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_datetime_now(bool isAsync) { await base.Where_datetime_now(isAsync); @@ -47,9 +55,11 @@ public override async Task Where_datetime_now(bool isAsync) SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE (CURRENT_TIMESTAMP() <> @__myDatetime_0) OR @__myDatetime_0 IS NULL"); +WHERE (CURRENT_TIMESTAMP() <> @__myDatetime_0) OR CURRENT_TIMESTAMP() IS NULL"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_datetime_utcnow(bool isAsync) { await base.Where_datetime_utcnow(isAsync); @@ -59,9 +69,11 @@ public override async Task Where_datetime_utcnow(bool isAsync) SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE (UTC_TIMESTAMP() <> @__myDatetime_0) OR @__myDatetime_0 IS NULL"); +WHERE (UTC_TIMESTAMP() <> @__myDatetime_0) OR UTC_TIMESTAMP() IS NULL"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_datetime_today(bool isAsync) { await base.Where_datetime_today(isAsync); @@ -69,9 +81,11 @@ public override async Task Where_datetime_today(bool isAsync) AssertSql( @"SELECT `e`.`EmployeeID`, `e`.`City`, `e`.`Country`, `e`.`FirstName`, `e`.`ReportsTo`, `e`.`Title` FROM `Employees` AS `e` -WHERE CONVERT(CURRENT_TIMESTAMP(), date) = CURDATE()"); +WHERE (CONVERT(CURRENT_TIMESTAMP(), date) = CURDATE()) OR (CONVERT(CURRENT_TIMESTAMP(), date) IS NULL AND CURDATE() IS NULL)"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_datetime_date_component(bool isAsync) { await base.Where_datetime_date_component(isAsync); @@ -81,9 +95,11 @@ public override async Task Where_datetime_date_component(bool isAsync) SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE ((CONVERT(`o`.`OrderDate`, date) = @__myDatetime_0) AND (CONVERT(`o`.`OrderDate`, date) IS NOT NULL AND @__myDatetime_0 IS NOT NULL)) OR (CONVERT(`o`.`OrderDate`, date) IS NULL AND @__myDatetime_0 IS NULL)"); +WHERE CONVERT(`o`.`OrderDate`, date) = @__myDatetime_0"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_datetime_year_component(bool isAsync) { await base.Where_datetime_year_component(isAsync); @@ -91,9 +107,11 @@ public override async Task Where_datetime_year_component(bool isAsync) AssertSql( @"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (EXTRACT(year FROM `o`.`OrderDate`) = 1998) AND EXTRACT(year FROM `o`.`OrderDate`) IS NOT NULL"); +WHERE EXTRACT(year FROM `o`.`OrderDate`) = 1998"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_datetime_month_component(bool isAsync) { await base.Where_datetime_month_component(isAsync); @@ -101,9 +119,11 @@ public override async Task Where_datetime_month_component(bool isAsync) AssertSql( @"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (EXTRACT(month FROM `o`.`OrderDate`) = 4) AND EXTRACT(month FROM `o`.`OrderDate`) IS NOT NULL"); +WHERE EXTRACT(month FROM `o`.`OrderDate`) = 4"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_datetime_dayOfYear_component(bool isAsync) { await base.Where_datetime_dayOfYear_component(isAsync); @@ -111,9 +131,11 @@ public override async Task Where_datetime_dayOfYear_component(bool isAsync) AssertSql( @"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (DAYOFYEAR(`o`.`OrderDate`) = 68) AND DAYOFYEAR(`o`.`OrderDate`) IS NOT NULL"); +WHERE DAYOFYEAR(`o`.`OrderDate`) = 68"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_datetime_day_component(bool isAsync) { await base.Where_datetime_day_component(isAsync); @@ -121,9 +143,11 @@ public override async Task Where_datetime_day_component(bool isAsync) AssertSql( @"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (EXTRACT(day FROM `o`.`OrderDate`) = 4) AND EXTRACT(day FROM `o`.`OrderDate`) IS NOT NULL"); +WHERE EXTRACT(day FROM `o`.`OrderDate`) = 4"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_datetime_hour_component(bool isAsync) { await base.Where_datetime_hour_component(isAsync); @@ -131,9 +155,11 @@ public override async Task Where_datetime_hour_component(bool isAsync) AssertSql( @"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (EXTRACT(hour FROM `o`.`OrderDate`) = 14) AND EXTRACT(hour FROM `o`.`OrderDate`) IS NOT NULL"); +WHERE EXTRACT(hour FROM `o`.`OrderDate`) = 14"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_datetime_minute_component(bool isAsync) { await base.Where_datetime_minute_component(isAsync); @@ -141,9 +167,11 @@ public override async Task Where_datetime_minute_component(bool isAsync) AssertSql( @"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (EXTRACT(minute FROM `o`.`OrderDate`) = 23) AND EXTRACT(minute FROM `o`.`OrderDate`) IS NOT NULL"); +WHERE EXTRACT(minute FROM `o`.`OrderDate`) = 23"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_datetime_second_component(bool isAsync) { await base.Where_datetime_second_component(isAsync); @@ -151,9 +179,11 @@ public override async Task Where_datetime_second_component(bool isAsync) AssertSql( @"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (EXTRACT(second FROM `o`.`OrderDate`) = 44) AND EXTRACT(second FROM `o`.`OrderDate`) IS NOT NULL"); +WHERE EXTRACT(second FROM `o`.`OrderDate`) = 44"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_datetime_millisecond_component(bool isAsync) { await base.Where_datetime_millisecond_component(isAsync); @@ -164,6 +194,8 @@ public override async Task Where_datetime_millisecond_component(bool isAsync) WHERE (EXTRACT(microsecond FROM `o`.`OrderDate`)) DIV (1000) = 88"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task String_StartsWith_Literal(bool isAsync) { await base.String_StartsWith_Literal(isAsync); @@ -171,9 +203,11 @@ public override async Task String_StartsWith_Literal(bool isAsync) AssertSql( @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE `c`.`ContactName` IS NOT NULL AND ((`c`.`ContactName` LIKE CONCAT('M', '%')) AND ((LEFT(`c`.`ContactName`, CHAR_LENGTH(CONVERT('M' USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT('M' USING utf8mb4) COLLATE utf8mb4_bin) AND LEFT(`c`.`ContactName`, CHAR_LENGTH(CONVERT('M' USING utf8mb4) COLLATE utf8mb4_bin)) IS NOT NULL))"); +WHERE `c`.`ContactName` IS NOT NULL AND ((`c`.`ContactName` LIKE CONCAT('M', '%')) AND (LEFT(`c`.`ContactName`, CHAR_LENGTH(CONVERT('M' USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT('M' USING utf8mb4) COLLATE utf8mb4_bin))"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task String_StartsWith_Identity(bool isAsync) { await base.String_StartsWith_Identity(isAsync); @@ -181,9 +215,11 @@ public override async Task String_StartsWith_Identity(bool isAsync) AssertSql( @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE ((`c`.`ContactName` = '') AND `c`.`ContactName` IS NOT NULL) OR (`c`.`ContactName` IS NOT NULL AND (`c`.`ContactName` IS NOT NULL AND ((`c`.`ContactName` LIKE CONCAT(`c`.`ContactName`, '%')) AND (((LEFT(`c`.`ContactName`, CHAR_LENGTH(CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin) AND (LEFT(`c`.`ContactName`, CHAR_LENGTH(CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin)) IS NOT NULL AND CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin IS NOT NULL)) OR (LEFT(`c`.`ContactName`, CHAR_LENGTH(CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin)) IS NULL AND CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin IS NULL)))))"); +WHERE (`c`.`ContactName` = '') OR (`c`.`ContactName` IS NOT NULL AND (`c`.`ContactName` IS NOT NULL AND ((`c`.`ContactName` LIKE CONCAT(`c`.`ContactName`, '%')) AND (LEFT(`c`.`ContactName`, CHAR_LENGTH(CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin))))"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task String_StartsWith_Column(bool isAsync) { await base.String_StartsWith_Column(isAsync); @@ -191,9 +227,11 @@ public override async Task String_StartsWith_Column(bool isAsync) AssertSql( @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE ((`c`.`ContactName` = '') AND `c`.`ContactName` IS NOT NULL) OR (`c`.`ContactName` IS NOT NULL AND (`c`.`ContactName` IS NOT NULL AND ((`c`.`ContactName` LIKE CONCAT(`c`.`ContactName`, '%')) AND (((LEFT(`c`.`ContactName`, CHAR_LENGTH(CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin) AND (LEFT(`c`.`ContactName`, CHAR_LENGTH(CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin)) IS NOT NULL AND CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin IS NOT NULL)) OR (LEFT(`c`.`ContactName`, CHAR_LENGTH(CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin)) IS NULL AND CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin IS NULL)))))"); +WHERE (`c`.`ContactName` = '') OR (`c`.`ContactName` IS NOT NULL AND (`c`.`ContactName` IS NOT NULL AND ((`c`.`ContactName` LIKE CONCAT(`c`.`ContactName`, '%')) AND (LEFT(`c`.`ContactName`, CHAR_LENGTH(CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin))))"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task String_StartsWith_MethodCall(bool isAsync) { await base.String_StartsWith_MethodCall(isAsync); @@ -201,9 +239,11 @@ public override async Task String_StartsWith_MethodCall(bool isAsync) AssertSql( @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE `c`.`ContactName` IS NOT NULL AND ((`c`.`ContactName` LIKE CONCAT('M', '%')) AND ((LEFT(`c`.`ContactName`, CHAR_LENGTH(CONVERT('M' USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT('M' USING utf8mb4) COLLATE utf8mb4_bin) AND LEFT(`c`.`ContactName`, CHAR_LENGTH(CONVERT('M' USING utf8mb4) COLLATE utf8mb4_bin)) IS NOT NULL))"); +WHERE `c`.`ContactName` IS NOT NULL AND ((`c`.`ContactName` LIKE CONCAT('M', '%')) AND (LEFT(`c`.`ContactName`, CHAR_LENGTH(CONVERT('M' USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT('M' USING utf8mb4) COLLATE utf8mb4_bin))"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task String_EndsWith_Literal(bool isAsync) { await base.String_EndsWith_Literal(isAsync); @@ -211,9 +251,11 @@ public override async Task String_EndsWith_Literal(bool isAsync) AssertSql( @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE `c`.`ContactName` IS NOT NULL AND ((RIGHT(`c`.`ContactName`, CHAR_LENGTH(CONVERT('b' USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT('b' USING utf8mb4) COLLATE utf8mb4_bin) AND RIGHT(`c`.`ContactName`, CHAR_LENGTH(CONVERT('b' USING utf8mb4) COLLATE utf8mb4_bin)) IS NOT NULL)"); +WHERE `c`.`ContactName` IS NOT NULL AND (RIGHT(`c`.`ContactName`, CHAR_LENGTH(CONVERT('b' USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT('b' USING utf8mb4) COLLATE utf8mb4_bin)"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task String_EndsWith_Identity(bool isAsync) { await base.String_EndsWith_Identity(isAsync); @@ -221,9 +263,11 @@ public override async Task String_EndsWith_Identity(bool isAsync) AssertSql( @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE ((`c`.`ContactName` = '') AND `c`.`ContactName` IS NOT NULL) OR (`c`.`ContactName` IS NOT NULL AND (`c`.`ContactName` IS NOT NULL AND ((((RIGHT(`c`.`ContactName`, CHAR_LENGTH(CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin) AND (RIGHT(`c`.`ContactName`, CHAR_LENGTH(CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin)) IS NOT NULL AND CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin IS NOT NULL)) OR (RIGHT(`c`.`ContactName`, CHAR_LENGTH(CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin)) IS NULL AND CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin IS NULL)) OR ((`c`.`ContactName` = '') AND `c`.`ContactName` IS NOT NULL))))"); +WHERE (`c`.`ContactName` = '') OR (`c`.`ContactName` IS NOT NULL AND (`c`.`ContactName` IS NOT NULL AND ((RIGHT(`c`.`ContactName`, CHAR_LENGTH(CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin) OR (`c`.`ContactName` = ''))))"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task String_EndsWith_Column(bool isAsync) { await base.String_EndsWith_Column(isAsync); @@ -231,9 +275,11 @@ public override async Task String_EndsWith_Column(bool isAsync) AssertSql( @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE ((`c`.`ContactName` = '') AND `c`.`ContactName` IS NOT NULL) OR (`c`.`ContactName` IS NOT NULL AND (`c`.`ContactName` IS NOT NULL AND ((((RIGHT(`c`.`ContactName`, CHAR_LENGTH(CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin) AND (RIGHT(`c`.`ContactName`, CHAR_LENGTH(CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin)) IS NOT NULL AND CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin IS NOT NULL)) OR (RIGHT(`c`.`ContactName`, CHAR_LENGTH(CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin)) IS NULL AND CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin IS NULL)) OR ((`c`.`ContactName` = '') AND `c`.`ContactName` IS NOT NULL))))"); +WHERE (`c`.`ContactName` = '') OR (`c`.`ContactName` IS NOT NULL AND (`c`.`ContactName` IS NOT NULL AND ((RIGHT(`c`.`ContactName`, CHAR_LENGTH(CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin) OR (`c`.`ContactName` = ''))))"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task String_EndsWith_MethodCall(bool isAsync) { await base.String_EndsWith_MethodCall(isAsync); @@ -241,9 +287,11 @@ public override async Task String_EndsWith_MethodCall(bool isAsync) AssertSql( @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE `c`.`ContactName` IS NOT NULL AND ((RIGHT(`c`.`ContactName`, CHAR_LENGTH(CONVERT('m' USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT('m' USING utf8mb4) COLLATE utf8mb4_bin) AND RIGHT(`c`.`ContactName`, CHAR_LENGTH(CONVERT('m' USING utf8mb4) COLLATE utf8mb4_bin)) IS NOT NULL)"); +WHERE `c`.`ContactName` IS NOT NULL AND (RIGHT(`c`.`ContactName`, CHAR_LENGTH(CONVERT('m' USING utf8mb4) COLLATE utf8mb4_bin)) = CONVERT('m' USING utf8mb4) COLLATE utf8mb4_bin)"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task String_Contains_Literal(bool isAsync) { await base.String_Contains_Literal(isAsync); @@ -254,6 +302,8 @@ public override async Task String_Contains_Literal(bool isAsync) WHERE LOCATE(CONVERT('M' USING utf8mb4) COLLATE utf8mb4_bin, `c`.`ContactName`) > 0"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task String_Contains_Identity(bool isAsync) { await base.String_Contains_Identity(isAsync); @@ -261,9 +311,11 @@ public override async Task String_Contains_Identity(bool isAsync) AssertSql( @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE (LOCATE(CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin, `c`.`ContactName`) > 0) OR ((`c`.`ContactName` = '') AND `c`.`ContactName` IS NOT NULL)"); +WHERE (LOCATE(CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin, `c`.`ContactName`) > 0) OR (`c`.`ContactName` = '')"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task String_Contains_Column(bool isAsync) { await base.String_Contains_Column(isAsync); @@ -271,9 +323,11 @@ public override async Task String_Contains_Column(bool isAsync) AssertSql( @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE (LOCATE(CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin, `c`.`ContactName`) > 0) OR ((`c`.`ContactName` = '') AND `c`.`ContactName` IS NOT NULL)"); +WHERE (LOCATE(CONVERT(`c`.`ContactName` USING utf8mb4) COLLATE utf8mb4_bin, `c`.`ContactName`) > 0) OR (`c`.`ContactName` = '')"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task String_Contains_MethodCall(bool isAsync) { await base.String_Contains_MethodCall(isAsync); @@ -284,6 +338,8 @@ public override async Task String_Contains_MethodCall(bool isAsync) WHERE LOCATE(CONVERT('M' USING utf8mb4) COLLATE utf8mb4_bin, `c`.`ContactName`) > 0"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task IsNullOrWhiteSpace_in_predicate(bool isAsync) { await base.IsNullOrWhiteSpace_in_predicate(isAsync); @@ -291,18 +347,22 @@ public override async Task IsNullOrWhiteSpace_in_predicate(bool isAsync) AssertSql( @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE `c`.`Region` IS NULL OR ((TRIM(`c`.`Region`) = '') AND TRIM(`c`.`Region`) IS NOT NULL)"); +WHERE `c`.`Region` IS NULL OR (TRIM(`c`.`Region`) = '')"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_string_length(bool isAsync) { await base.Where_string_length(isAsync); AssertSql( @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE (CHAR_LENGTH(`c`.`City`) = 6) AND CHAR_LENGTH(`c`.`City`) IS NOT NULL"); +WHERE CHAR_LENGTH(`c`.`City`) = 6"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_string_indexof(bool isAsync) { await base.Where_string_indexof(isAsync); @@ -310,9 +370,11 @@ public override async Task Where_string_indexof(bool isAsync) AssertSql( @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE ((LOCATE(CONVERT('Sea' USING utf8mb4) COLLATE utf8mb4_bin, `c`.`City`) - 1) <> -1) OR LOCATE(CONVERT('Sea' USING utf8mb4) COLLATE utf8mb4_bin, `c`.`City`) - 1 IS NULL"); +WHERE ((LOCATE(CONVERT('Sea' USING utf8mb4) COLLATE utf8mb4_bin, `c`.`City`) - 1) <> -1) OR LOCATE(CONVERT('Sea' USING utf8mb4) COLLATE utf8mb4_bin, `c`.`City`) IS NULL"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Indexof_with_emptystring(bool isAsync) { await base.Indexof_with_emptystring(isAsync); @@ -323,6 +385,8 @@ public override async Task Indexof_with_emptystring(bool isAsync) WHERE `c`.`CustomerID` = 'ALFKI'"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_string_replace(bool isAsync) { await base.Where_string_replace(isAsync); @@ -330,9 +394,11 @@ public override async Task Where_string_replace(bool isAsync) AssertSql( @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE (REPLACE(`c`.`City`, 'Sea', 'Rea') = 'Reattle') AND REPLACE(`c`.`City`, 'Sea', 'Rea') IS NOT NULL"); +WHERE REPLACE(`c`.`City`, 'Sea', 'Rea') = 'Reattle'"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Replace_with_emptystring(bool isAsync) { await base.Replace_with_emptystring(isAsync); @@ -343,6 +409,8 @@ public override async Task Replace_with_emptystring(bool isAsync) WHERE `c`.`CustomerID` = 'ALFKI'"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_string_substring(bool isAsync) { await base.Where_string_substring(isAsync); @@ -350,9 +418,11 @@ public override async Task Where_string_substring(bool isAsync) AssertSql( @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE (SUBSTRING(`c`.`City`, 1 + 1, 2) = 'ea') AND SUBSTRING(`c`.`City`, 1 + 1, 2) IS NOT NULL"); +WHERE SUBSTRING(`c`.`City`, 1 + 1, 2) = 'ea'"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Substring_with_zero_startindex(bool isAsync) { await base.Substring_with_zero_startindex(isAsync); @@ -363,6 +433,8 @@ public override async Task Substring_with_zero_startindex(bool isAsync) WHERE `c`.`CustomerID` = 'ALFKI'"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Substring_with_constant(bool isAsync) { await base.Substring_with_constant(isAsync); @@ -373,6 +445,8 @@ public override async Task Substring_with_constant(bool isAsync) WHERE `c`.`CustomerID` = 'ALFKI'"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Substring_with_closure(bool isAsync) { await base.Substring_with_closure(isAsync); @@ -385,6 +459,8 @@ SELECT SUBSTRING(`c`.`ContactName`, @__start_0 + 1, 3) WHERE `c`.`CustomerID` = 'ALFKI'"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Substring_with_zero_length(bool isAsync) { await base.Substring_with_zero_length(isAsync); @@ -395,6 +471,8 @@ public override async Task Substring_with_zero_length(bool isAsync) WHERE `c`.`CustomerID` = 'ALFKI'"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_math_abs1(bool isAsync) { await base.Where_math_abs1(isAsync); @@ -405,6 +483,8 @@ public override async Task Where_math_abs1(bool isAsync) WHERE ABS(`o`.`ProductID`) > 10"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_math_abs2(bool isAsync) { await base.Where_math_abs2(isAsync); @@ -415,6 +495,8 @@ public override async Task Where_math_abs2(bool isAsync) WHERE ABS(`o`.`Quantity`) > 10"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_math_abs_uncorrelated(bool isAsync) { await base.Where_math_abs_uncorrelated(isAsync); @@ -425,6 +507,8 @@ public override async Task Where_math_abs_uncorrelated(bool isAsync) WHERE 10 < `o`.`ProductID`"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Select_math_round_int(bool isAsync) { await base.Select_math_round_int(isAsync); @@ -445,6 +529,8 @@ public override async Task Select_math_round_int(bool isAsync) } } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_math_min(bool isAsync) { await base.Where_math_min(isAsync); @@ -455,6 +541,8 @@ public override async Task Where_math_min(bool isAsync) WHERE (`o`.`OrderID` = 11077) AND (LEAST(`o`.`OrderID`, `o`.`ProductID`) = `o`.`ProductID`)"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_math_max(bool isAsync) { await base.Where_math_max(isAsync); @@ -465,6 +553,8 @@ public override async Task Where_math_max(bool isAsync) WHERE (`o`.`OrderID` = 11077) AND (GREATEST(`o`.`OrderID`, `o`.`ProductID`) = `o`.`OrderID`)"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_string_to_lower(bool isAsync) { await base.Where_string_to_lower(isAsync); @@ -475,6 +565,8 @@ public override async Task Where_string_to_lower(bool isAsync) WHERE LOWER(`c`.`CustomerID`) = 'alfki'"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Where_string_to_upper(bool isAsync) { await base.Where_string_to_upper(isAsync); @@ -485,6 +577,8 @@ public override async Task Where_string_to_upper(bool isAsync) WHERE UPPER(`c`.`CustomerID`) = 'ALFKI'"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task TrimStart_without_arguments_in_predicate(bool isAsync) { await base.TrimStart_without_arguments_in_predicate(isAsync); @@ -492,9 +586,11 @@ public override async Task TrimStart_without_arguments_in_predicate(bool isAsync AssertSql( @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE (TRIM(LEADING FROM `c`.`ContactTitle`) = 'Owner') AND TRIM(LEADING FROM `c`.`ContactTitle`) IS NOT NULL"); +WHERE TRIM(LEADING FROM `c`.`ContactTitle`) = 'Owner'"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task TrimStart_with_char_argument_in_predicate(bool isAsync) { await base.TrimStart_with_char_argument_in_predicate(isAsync); @@ -502,9 +598,11 @@ public override async Task TrimStart_with_char_argument_in_predicate(bool isAsyn AssertSql( @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE (TRIM(LEADING 'O' FROM `c`.`ContactTitle`) = 'wner') AND TRIM(LEADING 'O' FROM `c`.`ContactTitle`) IS NOT NULL"); +WHERE TRIM(LEADING 'O' FROM `c`.`ContactTitle`) = 'wner'"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override Task TrimStart_with_char_array_argument_in_predicate(bool isAsync) { // MySQL only supports a string (characters in fixed order) as the parameter specifying what should be trimmed. @@ -513,6 +611,8 @@ public override Task TrimStart_with_char_array_argument_in_predicate(bool isAsyn return Assert.ThrowsAsync(() => base.TrimStart_with_char_array_argument_in_predicate(isAsync)); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task TrimEnd_without_arguments_in_predicate(bool isAsync) { await base.TrimEnd_without_arguments_in_predicate(isAsync); @@ -520,9 +620,11 @@ public override async Task TrimEnd_without_arguments_in_predicate(bool isAsync) AssertSql( @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE (TRIM(TRAILING FROM `c`.`ContactTitle`) = 'Owner') AND TRIM(TRAILING FROM `c`.`ContactTitle`) IS NOT NULL"); +WHERE TRIM(TRAILING FROM `c`.`ContactTitle`) = 'Owner'"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task TrimEnd_with_char_argument_in_predicate(bool isAsync) { await base.TrimEnd_with_char_argument_in_predicate(isAsync); @@ -530,9 +632,11 @@ public override async Task TrimEnd_with_char_argument_in_predicate(bool isAsync) AssertSql( @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE (TRIM(TRAILING 'r' FROM `c`.`ContactTitle`) = 'Owne') AND TRIM(TRAILING 'r' FROM `c`.`ContactTitle`) IS NOT NULL"); +WHERE TRIM(TRAILING 'r' FROM `c`.`ContactTitle`) = 'Owne'"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override Task TrimEnd_with_char_array_argument_in_predicate(bool isAsync) { // MySQL only supports a string (characters in fixed order) as the parameter specifying what should be trimmed. @@ -541,6 +645,8 @@ public override Task TrimEnd_with_char_array_argument_in_predicate(bool isAsync) return Assert.ThrowsAsync(() => base.TrimEnd_with_char_array_argument_in_predicate(isAsync)); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Trim_without_argument_in_predicate(bool isAsync) { await base.Trim_without_argument_in_predicate(isAsync); @@ -548,9 +654,11 @@ public override async Task Trim_without_argument_in_predicate(bool isAsync) AssertSql( @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE (TRIM(`c`.`ContactTitle`) = 'Owner') AND TRIM(`c`.`ContactTitle`) IS NOT NULL"); +WHERE TRIM(`c`.`ContactTitle`) = 'Owner'"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Trim_with_char_argument_in_predicate(bool isAsync) { await base.Trim_with_char_argument_in_predicate(isAsync); @@ -558,9 +666,11 @@ public override async Task Trim_with_char_argument_in_predicate(bool isAsync) AssertSql( @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE (TRIM('O' FROM `c`.`ContactTitle`) = 'wner') AND TRIM('O' FROM `c`.`ContactTitle`) IS NOT NULL"); +WHERE TRIM('O' FROM `c`.`ContactTitle`) = 'wner'"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override Task Trim_with_char_array_argument_in_predicate(bool isAsync) { // MySQL only supports a string (characters in fixed order) as the parameter specifying what should be trimmed. @@ -569,6 +679,8 @@ public override Task Trim_with_char_array_argument_in_predicate(bool isAsync) return Assert.ThrowsAsync(() => base.Trim_with_char_array_argument_in_predicate(isAsync)); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Sum_with_coalesce(bool isAsync) { await base.Sum_with_coalesce(isAsync); @@ -579,6 +691,8 @@ public override async Task Sum_with_coalesce(bool isAsync) WHERE `p`.`ProductID` < 40"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Select_datetime_year_component(bool isAsync) { await base.Select_datetime_year_component(isAsync); @@ -588,6 +702,8 @@ public override async Task Select_datetime_year_component(bool isAsync) FROM `Orders` AS `o`"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Select_datetime_month_component(bool isAsync) { await base.Select_datetime_month_component(isAsync); @@ -597,6 +713,8 @@ public override async Task Select_datetime_month_component(bool isAsync) FROM `Orders` AS `o`"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Select_datetime_day_of_year_component(bool isAsync) { await base.Select_datetime_day_of_year_component(isAsync); @@ -606,6 +724,8 @@ public override async Task Select_datetime_day_of_year_component(bool isAsync) FROM `Orders` AS `o`"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Select_datetime_day_component(bool isAsync) { await base.Select_datetime_day_component(isAsync); @@ -615,6 +735,8 @@ public override async Task Select_datetime_day_component(bool isAsync) FROM `Orders` AS `o`"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Select_datetime_hour_component(bool isAsync) { await base.Select_datetime_hour_component(isAsync); @@ -624,6 +746,8 @@ public override async Task Select_datetime_hour_component(bool isAsync) FROM `Orders` AS `o`"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Select_datetime_minute_component(bool isAsync) { await base.Select_datetime_minute_component(isAsync); @@ -633,6 +757,8 @@ public override async Task Select_datetime_minute_component(bool isAsync) FROM `Orders` AS `o`"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Select_datetime_second_component(bool isAsync) { await base.Select_datetime_second_component(isAsync); @@ -642,6 +768,8 @@ public override async Task Select_datetime_second_component(bool isAsync) FROM `Orders` AS `o`"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Select_datetime_millisecond_component(bool isAsync) { await base.Select_datetime_millisecond_component(isAsync); @@ -651,6 +779,8 @@ public override async Task Select_datetime_millisecond_component(bool isAsync) FROM `Orders` AS `o`"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override async Task Select_expression_references_are_updated_correctly_with_subquery(bool isAsync) { await base.Select_expression_references_are_updated_correctly_with_subquery(isAsync); @@ -663,117 +793,146 @@ SELECT DISTINCT EXTRACT(year FROM `o`.`OrderDate`) WHERE `o`.`OrderDate` IS NOT NULL AND (EXTRACT(year FROM `o`.`OrderDate`) < @__nextYear_0)"); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_equals_method_string_with_ignore_case(bool isAsync) + { + // We have an implementation for this and therefore don't throw. + return AssertQuery( + isAsync, + ss => ss.Set().Where(c => c.City.Equals("London", StringComparison.OrdinalIgnoreCase)), + entryCount: 6); + } + [ConditionalTheory(Skip = "issue #573")] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Project_single_element_from_collection_with_OrderBy_Take_and_FirstOrDefault(bool isAsync) { return base.Project_single_element_from_collection_with_OrderBy_Take_and_FirstOrDefault(isAsync); } [ConditionalTheory(Skip = "issue #573")] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Project_single_element_from_collection_with_OrderBy_Take_and_FirstOrDefault_with_parameter(bool isAsync) { return base.Project_single_element_from_collection_with_OrderBy_Take_and_FirstOrDefault_with_parameter(isAsync); } [ConditionalTheory(Skip = "issue #573")] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Project_single_element_from_collection_with_multiple_OrderBys_Take_and_FirstOrDefault(bool isAsync) { return base.Project_single_element_from_collection_with_multiple_OrderBys_Take_and_FirstOrDefault(isAsync); } [ConditionalTheory(Skip = "issue #573")] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Project_single_element_from_collection_with_multiple_OrderBys_Take_and_FirstOrDefault_followed_by_projection_of_length_property(bool isAsync) { return base.Project_single_element_from_collection_with_multiple_OrderBys_Take_and_FirstOrDefault_followed_by_projection_of_length_property(isAsync); } [ConditionalTheory(Skip = "issue #573")] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Project_single_element_from_collection_with_multiple_OrderBys_Take_and_FirstOrDefault_2(bool isAsync) { return base.Project_single_element_from_collection_with_multiple_OrderBys_Take_and_FirstOrDefault_2(isAsync); } [ConditionalTheory(Skip = "issue #573")] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Project_single_element_from_collection_with_OrderBy_over_navigation_Take_and_FirstOrDefault(bool isAsync) { return base.Project_single_element_from_collection_with_OrderBy_over_navigation_Take_and_FirstOrDefault(isAsync); } [ConditionalTheory(Skip = "issue #573")] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Where_as_queryable_expression(bool isAsync) { return base.Where_as_queryable_expression(isAsync); } [ConditionalTheory(Skip = "issue #552")] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Where_multiple_contains_in_subquery_with_and(bool isAsync) { return base.Where_multiple_contains_in_subquery_with_and(isAsync); } [ConditionalTheory(Skip = "issue #552")] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Where_multiple_contains_in_subquery_with_or(bool isAsync) { return base.Where_multiple_contains_in_subquery_with_or(isAsync); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override Task Intersect(bool isAsync) { // INTERSECT is not natively supported by MySQL. return Assert.ThrowsAsync(() => base.Intersect(isAsync)); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override Task Intersect_nested(bool isAsync) { // INTERSECT is not natively supported by MySQL. return Assert.ThrowsAsync(() => base.Intersect_nested(isAsync)); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override Task Intersect_non_entity(bool isAsync) { // INTERSECT is not natively supported by MySQL. return Assert.ThrowsAsync(() => base.Intersect_non_entity(isAsync)); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override Task Union_Intersect(bool isAsync) { // INTERSECT is not natively supported by MySQL. return Assert.ThrowsAsync(() => base.Union_Intersect(isAsync)); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override Task Except(bool isAsync) { // EXCEPT is not natively supported by MySQL. return Assert.ThrowsAsync(() => base.Except(isAsync)); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override Task Except_simple_followed_by_projecting_constant(bool isAsync) { // EXCEPT is not natively supported by MySQL. return Assert.ThrowsAsync(() => base.Except_simple_followed_by_projecting_constant(isAsync)); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override Task Except_nested(bool isAsync) { // EXCEPT is not natively supported by MySQL. return Assert.ThrowsAsync(() => base.Except_nested(isAsync)); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override Task Except_non_entity(bool isAsync) { // EXCEPT is not natively supported by MySQL. return Assert.ThrowsAsync(() => base.Except_non_entity(isAsync)); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] public override Task Select_Except_reference_projection(bool isAsync) { // EXCEPT is not natively supported by MySQL. @@ -781,7 +940,7 @@ public override Task Select_Except_reference_projection(bool isAsync) } [SupportedServerVersionTheory(ServerVersion.CrossApplySupportKey)] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task SelectMany_correlated_with_outer_1(bool isAsync) { return base.SelectMany_correlated_with_outer_1(isAsync); @@ -789,14 +948,14 @@ public override Task SelectMany_correlated_with_outer_1(bool isAsync) // [SupportedServerVersionTheory(ServerVersion.CrossApplySupportKey)] [ConditionalTheory(Skip = "Leads to a different result set in CI on Linux with MySQL 8.0.17. TODO: Needs investigation!")] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task SelectMany_correlated_with_outer_2(bool isAsync) { return base.SelectMany_correlated_with_outer_2(isAsync); } [SupportedServerVersionTheory(ServerVersion.OuterApplySupportKey)] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task SelectMany_correlated_with_outer_3(bool isAsync) { return base.SelectMany_correlated_with_outer_3(isAsync); @@ -804,14 +963,14 @@ public override Task SelectMany_correlated_with_outer_3(bool isAsync) // [SupportedServerVersionTheory(ServerVersion.CrossApplySupportKey)] [ConditionalTheory(Skip = "Leads to a different result set in CI on Linux with MySQL 8.0.17. TODO: Needs investigation!")] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task SelectMany_correlated_with_outer_4(bool isAsync) { return base.SelectMany_correlated_with_outer_4(isAsync); } [SupportedServerVersionTheory(ServerVersion.OuterApplySupportKey)] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Project_single_element_from_collection_with_OrderBy_over_navigation_Take_and_FirstOrDefault_2(bool isAsync) { return base.Project_single_element_from_collection_with_OrderBy_over_navigation_Take_and_FirstOrDefault_2(isAsync); @@ -824,20 +983,21 @@ public override void Select_nested_collection_multi_level() } [SupportedServerVersionTheory(ServerVersion.OuterApplySupportKey)] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Project_single_element_from_collection_with_OrderBy_Distinct_and_FirstOrDefault_followed_by_projecting_length(bool isAsync) { return base.Project_single_element_from_collection_with_OrderBy_Distinct_and_FirstOrDefault_followed_by_projecting_length(isAsync); } [SupportedServerVersionTheory(ServerVersion.OuterApplySupportKey)] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task Project_single_element_from_collection_with_OrderBy_Take_and_SingleOrDefault(bool isAsync) { return base.Project_single_element_from_collection_with_OrderBy_Take_and_SingleOrDefault(isAsync); } [ConditionalTheory(Skip = "TODO: MySQL does not seem to allow an ORDER BY or LIMIT clause directly in a SELECT statement that is part of a UNION.")] + [MemberData(nameof(IsAsyncData))] public override Task Union_Take_Union_Take(bool isAsync) { // TODO: MySQL does not seem to allow an ORDER BY or LIMIT clause directly in a SELECT statement that is part of a UNION. @@ -847,12 +1007,62 @@ public override Task Union_Take_Union_Take(bool isAsync) } [SupportedServerVersionTheory(ServerVersion.WindowFunctionsSupportKey)] - [MemberData("IsAsyncData")] + [MemberData(nameof(IsAsyncData))] public override Task SelectMany_Joined_Take(bool isAsync) { return base.SelectMany_Joined_Take(isAsync); } + [SupportedServerVersionTheory(ServerVersion.OuterApplySupportKey)] + [MemberData(nameof(IsAsyncData))] + public override Task Complex_nested_query_doesnt_try_binding_to_grandparent_when_parent_returns_complex_result(bool isAsync) + { + // MySql.Data.MySqlClient.MySqlException: Reference 'CustomerID' not supported (forward reference in item list) + return Assert.ThrowsAsync(() => base.Complex_nested_query_doesnt_try_binding_to_grandparent_when_parent_returns_complex_result(isAsync)); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Member_binding_after_ctor_arguments_fails_with_client_eval(bool isAsync) + { + return AssertTranslationFailed(() => base.Member_binding_after_ctor_arguments_fails_with_client_eval(isAsync)); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Union_Select_scalar(bool isAsync) + { + return AssertTranslationFailed(() => base.Union_Select_scalar(isAsync)); + } + + [SupportedServerVersionTheory(ServerVersion.OuterApplySupportKey)] + [MemberData(nameof(IsAsyncData))] + public override Task AsQueryable_in_query_server_evals(bool isAsync) + { + return base.AsQueryable_in_query_server_evals(isAsync); + } + + [SupportedServerVersionTheory(ServerVersion.CrossApplySupportKey)] + [MemberData(nameof(IsAsyncData))] + public override Task SelectMany_correlated_subquery_hard(bool isAsync) + { + return base.SelectMany_correlated_subquery_hard(isAsync); + } + + [SupportedServerVersionTheory(ServerVersion.CrossApplySupportKey)] + [MemberData(nameof(IsAsyncData))] + public override Task SelectMany_whose_selector_references_outer_source(bool isAsync) + { + return base.SelectMany_whose_selector_references_outer_source(isAsync); + } + + [SupportedServerVersionTheory(ServerVersion.CrossApplySupportKey)] + [MemberData(nameof(IsAsyncData))] + public override Task SelectMany_with_collection_being_correlated_subquery_which_references_inner_and_outer_entity(bool isAsync) + { + return base.SelectMany_with_collection_being_correlated_subquery_which_references_inner_and_outer_entity(isAsync); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); } diff --git a/test/EFCore.MySql.FunctionalTests/TestUtilities/MySqlTestStore.cs b/test/EFCore.MySql.FunctionalTests/TestUtilities/MySqlTestStore.cs index bb946e171..ff06d0097 100644 --- a/test/EFCore.MySql.FunctionalTests/TestUtilities/MySqlTestStore.cs +++ b/test/EFCore.MySql.FunctionalTests/TestUtilities/MySqlTestStore.cs @@ -22,8 +22,8 @@ public class MySqlTestStore : RelationalTestStore private readonly bool _useConnectionString; private readonly bool _noBackslashEscapes; - protected override string OpenDelimeter => "`"; - protected override string CloseDelimeter => "`"; + protected override string OpenDelimiter => "`"; + protected override string CloseDelimiter => "`"; public static MySqlTestStore GetOrCreate(string name, bool useConnectionString = false, bool noBackslashEscapes = false) => new MySqlTestStore(name, useConnectionString: useConnectionString, shared: true, noBackslashEscapes: noBackslashEscapes); diff --git a/test/EFCore.MySql.IntegrationTests/EFCore.MySql.IntegrationTests.csproj b/test/EFCore.MySql.IntegrationTests/EFCore.MySql.IntegrationTests.csproj index 5bf980f0b..ef24b047f 100644 --- a/test/EFCore.MySql.IntegrationTests/EFCore.MySql.IntegrationTests.csproj +++ b/test/EFCore.MySql.IntegrationTests/EFCore.MySql.IntegrationTests.csproj @@ -1,7 +1,7 @@  - netcoreapp3.0 + $(DefaultNetCoreTargetFramework) Pomelo.EntityFrameworkCore.MySql.IntegrationTests Pomelo.EntityFrameworkCore.MySql.IntegrationTests.Program Exe @@ -12,9 +12,14 @@ Pomelo.EntityFrameworkCore.MySql.IntegrationTests + + $(MSBuildWarningsAsMessages);$(NoWarn) + + + @@ -55,7 +60,7 @@ - $(LocalMySqlConnectorRepository)\src\MySqlConnector\bin\Debug\$(TargetFramework)\MySqlConnector.dll + $(LocalMySqlConnectorRepository)\src\MySqlConnector\bin\Debug\$(DefaultNetStandardTargetFramework)\MySqlConnector.dll diff --git a/test/EFCore.MySql.IntegrationTests/scripts/scaffold.sh b/test/EFCore.MySql.IntegrationTests/scripts/scaffold.sh index ed493e131..00115aaf8 100755 --- a/test/EFCore.MySql.IntegrationTests/scripts/scaffold.sh +++ b/test/EFCore.MySql.IntegrationTests/scripts/scaffold.sh @@ -8,7 +8,7 @@ rm -rf Scaffold mkdir -p Scaffold connection_string=$(dotnet run connectionString | tail -1) -./scripts/dotnet-ef.sh dbcontext scaffold -o "Scaffold" -t "DataTypesSimple" -t "DataTypesVariable" "$connection_string" "Pomelo.EntityFrameworkCore.MySql" +./scripts/dotnet-ef.sh dbcontext scaffold "$connection_string" "Pomelo.EntityFrameworkCore.MySql" --output-dir "Scaffold" --table "DataTypesSimple" --table "DataTypesVariable" error=false files=( "DataTypesSimple.cs" "DataTypesVariable.cs" ) diff --git a/test/EFCore.MySql.Tests/EFCore.MySql.Tests.csproj b/test/EFCore.MySql.Tests/EFCore.MySql.Tests.csproj index e67dd514b..f87612c33 100644 --- a/test/EFCore.MySql.Tests/EFCore.MySql.Tests.csproj +++ b/test/EFCore.MySql.Tests/EFCore.MySql.Tests.csproj @@ -1,13 +1,17 @@  - netcoreapp3.0 + $(DefaultNetCoreTargetFramework) true Pomelo.EntityFrameworkCore.MySql.Tests Pomelo.EntityFrameworkCore.MySql $(DefaultItemExcludes);*.trx + + $(MSBuildWarningsAsMessages);$(NoWarn) + + PreserveNewest @@ -75,7 +79,7 @@ - $(LocalMySqlConnectorRepository)\src\MySqlConnector\bin\Debug\$(TargetFramework)\MySqlConnector.dll + $(LocalMySqlConnectorRepository)\src\MySqlConnector\bin\Debug\$(DefaultNetStandardTargetFramework)\MySqlConnector.dll