From a2c32f1f4356ccf7076ff265dc3c131eab24bf13 Mon Sep 17 00:00:00 2001 From: maumar Date: Thu, 26 Aug 2021 13:51:55 -0700 Subject: [PATCH] Adding some regression tests for issues fixed earlier Resolves #19927 Resolves #22701 --- .../Query/NorthwindSelectQueryCosmosTest.cs | 6 + .../Query/GearsOfWarQueryInMemoryTest.cs | 6 + .../Query/GearsOfWarQueryFixtureBase.cs | 16 ++ .../Query/GearsOfWarQueryTestBase.cs | 140 ++++++++++++++++++ .../Query/NorthwindSelectQueryTestBase.cs | 2 +- .../Query/GearsOfWarQuerySqlServerTest.cs | 42 ++++++ .../NorthwindSelectQuerySqlServerTest.cs | 11 ++ .../Query/TPTGearsOfWarQuerySqlServerTest.cs | 58 ++++++++ 8 files changed, 280 insertions(+), 1 deletion(-) diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs index b8fde3f25da..44b895e4bb3 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs @@ -1314,6 +1314,12 @@ public override Task Client_projection_with_string_initialization_with_scalar_su return base.Client_projection_with_string_initialization_with_scalar_subquery(async); } + [ConditionalTheory(Skip = "Cross collection join Issue#17246")] + public override Task Projecting_count_of_navigation_which_is_generic_collection_using_convert(bool async) + { + return base.Projecting_count_of_navigation_which_is_generic_collection_using_convert(async); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); diff --git a/test/EFCore.InMemory.FunctionalTests/Query/GearsOfWarQueryInMemoryTest.cs b/test/EFCore.InMemory.FunctionalTests/Query/GearsOfWarQueryInMemoryTest.cs index 18507b1f537..23eaace61a2 100644 --- a/test/EFCore.InMemory.FunctionalTests/Query/GearsOfWarQueryInMemoryTest.cs +++ b/test/EFCore.InMemory.FunctionalTests/Query/GearsOfWarQueryInMemoryTest.cs @@ -70,5 +70,11 @@ public override async Task Projecting_some_properties_as_well_as_correlated_coll Assert.Equal(InMemoryStrings.DistinctOnSubqueryNotSupported, message); } + + [ConditionalTheory(Skip = "Issue #25735")] + public override Task Project_navigation_defined_on_derived_from_entity_with_inheritance_using_soft_cast(bool async) + { + return base.Project_navigation_defined_on_derived_from_entity_with_inheritance_using_soft_cast(async); + } } } diff --git a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryFixtureBase.cs b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryFixtureBase.cs index 5b8e0975af6..6c01217c4b7 100644 --- a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryFixtureBase.cs +++ b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryFixtureBase.cs @@ -293,6 +293,22 @@ public IReadOnlyDictionary GetEntityAsserters() Assert.Equal(ee.SynergyWithId, aa.SynergyWithId); } } + }, + { + typeof(LocustHighCommand), (e, a) => + { + Assert.Equal(e == null, a == null); + + if (a != null) + { + var ee = (LocustHighCommand)e; + var aa = (LocustHighCommand)a; + + Assert.Equal(ee.Id, aa.Id); + Assert.Equal(ee.IsOperational, aa.IsOperational); + Assert.Equal(ee.Name, aa.Name); + } + } } }.ToDictionary(e => e.Key, e => (object)e.Value); diff --git a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs index 3036e064e4c..5efddcda681 100644 --- a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs @@ -8978,6 +8978,146 @@ public virtual Task Contains_on_readonly_enumerable(bool async) ss => ss.Set().Where(w => _weaponTypes.Contains(w.AmmunitionType))); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Project_navigation_defined_on_base_from_entity_with_inheritance_using_soft_cast(bool async) + { + return AssertQuery( + async, + ss => ss.Set().Select(g => new + { + Gear = g, + Tag = (g as Officer).Tag, + IsNull = (g as Officer).Tag == null, + Property = (g as Officer).Nickname, + PropertyAfterNavigation = (g as Officer).Tag.Id, + NestedOuter = new + { + CityOfBirth = (g as Officer).CityOfBirth, + IsNull = (g as Officer).CityOfBirth == null, + Property = (g as Officer).Nickname, + PropertyAfterNavigation = (g as Officer).CityOfBirth.Name, + NestedInner = new + { + Squad = (g as Officer).Squad, + IsNull = (g as Officer).Squad == null, + Property = (g as Officer).Nickname, + PropertyAfterNavigation = (g as Officer).Squad.Id + } + } + }), + ss => ss.Set().Select(g => new + { + Gear = g, + Tag = g.Tag, + IsNull = g.Tag == null, + Property = g.Nickname, + PropertyAfterNavigation = g.Tag.Id, + NestedOuter = new + { + CityOfBirth = g.CityOfBirth, + IsNull = g.CityOfBirth == null, + Property = g.Nickname, + PropertyAfterNavigation = g.CityOfBirth.Name, + NestedInner = new + { + Squad = g.Squad, + IsNull = g.Squad == null, + Property = g.Nickname, + PropertyAfterNavigation = g.Squad.Id + } + } + }), + elementSorter: e => e.Gear.Nickname, + elementAsserter: (e, a) => + { + AssertEqual(e.Gear, a.Gear); + AssertEqual(e.Tag, a.Tag); + AssertEqual(e.IsNull, a.IsNull); + AssertEqual(e.Property, a.Property); + AssertEqual(e.PropertyAfterNavigation, a.PropertyAfterNavigation); + + AssertEqual(e.NestedOuter.CityOfBirth, a.NestedOuter.CityOfBirth); + AssertEqual(e.NestedOuter.IsNull, a.NestedOuter.IsNull); + AssertEqual(e.NestedOuter.Property, a.NestedOuter.Property); + AssertEqual(e.NestedOuter.PropertyAfterNavigation, a.NestedOuter.PropertyAfterNavigation); + + AssertEqual(e.NestedOuter.NestedInner.Squad, a.NestedOuter.NestedInner.Squad); + AssertEqual(e.NestedOuter.NestedInner.IsNull, a.NestedOuter.NestedInner.IsNull); + AssertEqual(e.NestedOuter.NestedInner.Property, a.NestedOuter.NestedInner.Property); + AssertEqual(e.NestedOuter.NestedInner.PropertyAfterNavigation, a.NestedOuter.NestedInner.PropertyAfterNavigation); + }); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Project_navigation_defined_on_derived_from_entity_with_inheritance_using_soft_cast(bool async) + { + return AssertQuery( + async, + ss => ss.Set().Select(l => new + { + Leader = l, + DefeatedBy = (l as LocustCommander).DefeatedBy, + IsNull = (l as LocustCommander).DefeatedBy == null, + Property = (l as LocustCommander).DefeatedByNickname, + PropertyAfterNavigation = (bool?)(l as LocustCommander).DefeatedBy.HasSoulPatch, + NestedOuter = new + { + CommandingFaction = (l as LocustCommander).CommandingFaction, + IsNull = (l as LocustCommander).CommandingFaction == null, + Property = (int?)(l as LocustCommander).HighCommandId, + PropertyAfterNavigation = (l as LocustCommander).CommandingFaction.Eradicated, + NestedInner = new + { + HighCommand = (l as LocustCommander).HighCommand, + IsNull = (l as LocustCommander).HighCommand == null, + Property = (l as LocustCommander).DefeatedBySquadId, + PropertyAfterNavigation = (l as LocustCommander).HighCommand.Name + } + } + }), + ss => ss.Set().Select(l => new + { + Leader = l, + DefeatedBy = (l as LocustCommander).DefeatedBy, + IsNull = (l as LocustCommander).DefeatedBy == null, + Property = (l as LocustCommander).DefeatedByNickname, + PropertyAfterNavigation = (bool?)(l as LocustCommander).DefeatedBy.HasSoulPatch, + NestedOuter = new + { + CommandingFaction = (l as LocustCommander).CommandingFaction, + IsNull = (l as LocustCommander).CommandingFaction == null, + Property = (int?)(l as LocustCommander).HighCommandId, + PropertyAfterNavigation = (l as LocustCommander).CommandingFaction.MaybeScalar(x => x.Eradicated), + NestedInner = new + { + HighCommand = (l as LocustCommander).HighCommand, + IsNull = (l as LocustCommander).HighCommand == null, + Property = (l as LocustCommander).MaybeScalar(x => x.DefeatedBySquadId), + PropertyAfterNavigation = (l as LocustCommander).HighCommand.Name + } + } + }), + elementSorter: e => e.Leader.Name, + elementAsserter: (e, a) => + { + AssertEqual(e.Leader, a.Leader); + AssertEqual(e.DefeatedBy, a.DefeatedBy); + AssertEqual(e.IsNull, a.IsNull); + AssertEqual(e.Property, a.Property); + AssertEqual(e.PropertyAfterNavigation, a.PropertyAfterNavigation); + AssertEqual(e.NestedOuter.CommandingFaction, a.NestedOuter.CommandingFaction); + AssertEqual(e.NestedOuter.IsNull, a.NestedOuter.IsNull); + AssertEqual(e.NestedOuter.Property, a.NestedOuter.Property); + AssertEqual(e.NestedOuter.PropertyAfterNavigation, a.NestedOuter.PropertyAfterNavigation); + AssertEqual(e.NestedOuter.NestedInner.HighCommand, a.NestedOuter.NestedInner.HighCommand); + AssertEqual(e.NestedOuter.NestedInner.IsNull, a.NestedOuter.NestedInner.IsNull); + AssertEqual(e.NestedOuter.NestedInner.Property, a.NestedOuter.NestedInner.Property); + AssertEqual(e.NestedOuter.NestedInner.PropertyAfterNavigation, a.NestedOuter.NestedInner.PropertyAfterNavigation); + }); + } + protected GearsOfWarContext CreateContext() => Fixture.CreateContext(); diff --git a/test/EFCore.Specification.Tests/Query/NorthwindSelectQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/NorthwindSelectQueryTestBase.cs index 9451a5b9d90..6c6a8f8e6ff 100644 --- a/test/EFCore.Specification.Tests/Query/NorthwindSelectQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/NorthwindSelectQueryTestBase.cs @@ -2038,7 +2038,7 @@ public virtual Task Projecting_count_of_navigation_which_is_generic_collection(b assertOrder: true); } - [ConditionalTheory(Skip = "issue #22701")] + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Projecting_count_of_navigation_which_is_generic_collection_using_convert(bool async) { diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs index fe025a6a8ac..ebe281dc370 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs @@ -8157,6 +8157,48 @@ FROM [Weapons] AS [w] WHERE [w].[AmmunitionType] = 1"); } + public override async Task Project_navigation_defined_on_base_from_entity_with_inheritance_using_soft_cast(bool async) + { + await base.Project_navigation_defined_on_base_from_entity_with_inheritance_using_soft_cast(async); + + AssertSql( + @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[IssueDate], [t].[Note], CASE + WHEN [t].[Id] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [IsNull], [c].[Name], [c].[Location], [c].[Nation], CASE + WHEN [c].[Name] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [IsNull], [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name], CASE + WHEN [s].[Id] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [IsNull] +FROM [Gears] AS [g] +LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) +LEFT JOIN [Cities] AS [c] ON [g].[CityOfBirthName] = [c].[Name] +LEFT JOIN [Squads] AS [s] ON [g].[SquadId] = [s].[Id]"); + } + + public override async Task Project_navigation_defined_on_derived_from_entity_with_inheritance_using_soft_cast(bool async) + { + await base.Project_navigation_defined_on_derived_from_entity_with_inheritance_using_soft_cast(async); + + AssertSql( + @"SELECT [l].[Name], [l].[Discriminator], [l].[LocustHordeId], [l].[ThreatLevel], [l].[ThreatLevelByte], [l].[ThreatLevelNullableByte], [l].[DefeatedByNickname], [l].[DefeatedBySquadId], [l].[HighCommandId], [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], CASE + WHEN [g].[Nickname] IS NULL OR [g].[SquadId] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [IsNull], [f].[Id], [f].[CapitalName], [f].[Discriminator], [f].[Name], [f].[ServerAddress], [f].[CommanderName], [f].[Eradicated], CASE + WHEN [f].[Id] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [IsNull], [l0].[Id], [l0].[IsOperational], [l0].[Name], CASE + WHEN [l0].[Id] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [IsNull] +FROM [LocustLeaders] AS [l] +LEFT JOIN [Gears] AS [g] ON ([l].[DefeatedByNickname] = [g].[Nickname]) AND ([l].[DefeatedBySquadId] = [g].[SquadId]) +LEFT JOIN [Factions] AS [f] ON [l].[Name] = [f].[CommanderName] +LEFT JOIN [LocustHighCommands] AS [l0] ON [l].[HighCommandId] = [l0].[Id]"); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs index d23c4989328..b92fe8faec3 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs @@ -1476,6 +1476,17 @@ FROM [Customers] AS [c] ORDER BY [c].[CustomerID]"); } + public override async Task Projecting_count_of_navigation_which_is_generic_collection_using_convert(bool async) + { + await base.Projecting_count_of_navigation_which_is_generic_collection_using_convert(async); + + AssertSql( + @"SELECT [c].[CustomerID], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +FROM [Customers] AS [c] +LEFT JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] +ORDER BY [c].[CustomerID]"); + } + public override async Task Projection_take_projection_doesnt_project_intermittent_column(bool async) { await base.Projection_take_projection_doesnt_project_intermittent_column(async); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs index 1a3dfa76fbb..954d7e7f02b 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs @@ -9087,6 +9087,64 @@ public override async Task Where_TimeOnly_subtract_TimeOnly(bool async) AssertSql(""); } + public override async Task Project_navigation_defined_on_base_from_entity_with_inheritance_using_soft_cast(bool async) + { + await base.Project_navigation_defined_on_base_from_entity_with_inheritance_using_soft_cast(async); + + AssertSql( + @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], CASE + WHEN [o].[Nickname] IS NOT NULL THEN N'Officer' +END AS [Discriminator], [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[IssueDate], [t].[Note], CASE + WHEN [t].[Id] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [IsNull], [c].[Name], [c].[Location], [c].[Nation], CASE + WHEN [c].[Name] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [IsNull], [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name], CASE + WHEN [s].[Id] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [IsNull] +FROM [Gears] AS [g] +LEFT JOIN [Officers] AS [o] ON ([g].[Nickname] = [o].[Nickname]) AND ([g].[SquadId] = [o].[SquadId]) +LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) +LEFT JOIN [Cities] AS [c] ON [g].[CityOfBirthName] = [c].[Name] +LEFT JOIN [Squads] AS [s] ON [g].[SquadId] = [s].[Id]"); + } + + public override async Task Project_navigation_defined_on_derived_from_entity_with_inheritance_using_soft_cast(bool async) + { + await base.Project_navigation_defined_on_derived_from_entity_with_inheritance_using_soft_cast(async); + + AssertSql( + @"SELECT [l].[Name], [l].[LocustHordeId], [l].[ThreatLevel], [l].[ThreatLevelByte], [l].[ThreatLevelNullableByte], [l0].[DefeatedByNickname], [l0].[DefeatedBySquadId], [l0].[HighCommandId], CASE + WHEN [l0].[Name] IS NOT NULL THEN N'LocustCommander' +END AS [Discriminator], [t].[Nickname], [t].[SquadId], [t].[AssignedCityName], [t].[CityOfBirthName], [t].[FullName], [t].[HasSoulPatch], [t].[LeaderNickname], [t].[LeaderSquadId], [t].[Rank], [t].[Discriminator], CASE + WHEN [t].[Nickname] IS NULL OR [t].[SquadId] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [IsNull], [t0].[Id], [t0].[CapitalName], [t0].[Name], [t0].[ServerAddress], [t0].[CommanderName], [t0].[Eradicated], CASE + WHEN [t0].[Id] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [IsNull], [l2].[Id], [l2].[IsOperational], [l2].[Name], CASE + WHEN [l2].[Id] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [IsNull] +FROM [LocustLeaders] AS [l] +LEFT JOIN [LocustCommanders] AS [l0] ON [l].[Name] = [l0].[Name] +LEFT JOIN ( + SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], CASE + WHEN [o].[Nickname] IS NOT NULL THEN N'Officer' + END AS [Discriminator] + FROM [Gears] AS [g] + LEFT JOIN [Officers] AS [o] ON ([g].[Nickname] = [o].[Nickname]) AND ([g].[SquadId] = [o].[SquadId]) +) AS [t] ON ([l0].[DefeatedByNickname] = [t].[Nickname]) AND ([l0].[DefeatedBySquadId] = [t].[SquadId]) +LEFT JOIN ( + SELECT [f].[Id], [f].[CapitalName], [f].[Name], [f].[ServerAddress], [l1].[CommanderName], [l1].[Eradicated] + FROM [Factions] AS [f] + INNER JOIN [LocustHordes] AS [l1] ON [f].[Id] = [l1].[Id] +) AS [t0] ON [l].[Name] = [t0].[CommanderName] +LEFT JOIN [LocustHighCommands] AS [l2] ON [l0].[HighCommandId] = [l2].[Id]"); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); }