From d65c26be8ee41eba6f0e540c8468b8d3a2be53a9 Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Tue, 28 Nov 2023 12:41:15 -0800 Subject: [PATCH] Move ModelBuilding tests to EFCore.Specification.Tests Fix found issues Part of #32315 --- .../Internal/SnapshotModelProcessor.cs | 3 +- ...nalCSharpRuntimeAnnotationCodeGenerator.cs | 13 +- .../Metadata/Internal/ColumnBase.cs | 9 + .../Metadata/Internal/RelationalModel.cs | 10 +- .../Metadata/Internal/TableMapping.cs | 40 + .../Metadata/Internal/TableMappingBase.cs | 11 +- .../Metadata/Internal/ViewMapping.cs | 40 + .../Metadata/RelationalAnnotationNames.cs | 74 + .../EFCore.Cosmos.FunctionalTests.csproj | 2 +- .../CosmosModelBuilderGenericTest.cs | 304 +-- .../CosmosTestModelBuilderExtensions.cs | 0 .../TestUtilities/CosmosModelAsserter.cs | 27 + .../TestUtilities/CosmosTestHelpers.cs | 2 + ...rpMigrationsGeneratorTest.ModelSnapshot.cs | 5 +- .../Design/CSharpMigrationsGeneratorTest.cs | 22 +- .../Design/SnapshotModelProcessorTest.cs | 6 +- .../Internal/CSharpDbContextGeneratorTest.cs | 4 +- .../Internal/CSharpEntityTypeGeneratorTest.cs | 4 +- .../Internal/ModelCodeGeneratorTestBase.cs | 15 +- .../EFCore.InMemory.FunctionalTests.csproj | 4 + .../InMemoryModelBuilderAssemblyScanTest.cs} | 4 +- ...elBuilderGenericRelationshipStringTest.cs} | 56 +- ...odelBuilderGenericRelationshipTypeTest.cs} | 26 +- .../InMemoryModelBuilderGenericTest.cs | 122 +- ...MemoryModelBuilderNonGenericStringTest.cs} | 46 +- .../InMemoryModelBuilderNonGenericTest.cs | 188 ++ ...BuilderNonGenericUnqualifiedStringTest.cs} | 16 +- .../ModelBuilding/InMemoryModelBuilderTest.cs | 79 + .../PropertyBagEntityTypeTest.cs | 0 .../RelationalModelBuilderTest.cs | 85 +- .../RelationalTestModelBuilderExtensions.cs | 0 .../Query/JsonQueryAdHocTestBase.cs | 2 +- .../CompiledModelRelationalTestBase.cs | 43 +- .../TestUtilities/RelationalModelAsserter.cs | 1772 +++++++++++++++++ .../TestUtilities/RelationalTestHelpers.cs | 1 + .../RelationalBuilderExtensionsTest.cs | 5 +- .../RelationalMetadataExtensionsTest.cs | 5 +- .../Metadata/RelationalModelTest.cs | 414 +--- .../TestUtilities/FakeDatabaseModelFactory.cs | 2 +- .../FakeRelationalTestHelpers.cs | 2 + .../TestUtilities/TestDbFunctions.cs | 10 - .../TestModificationCommandBatch.cs | 2 +- .../TestModificationCommandBatchFactory.cs | 2 +- .../TestProviderCodeGenerator.cs | 2 +- .../TestRelationalConventionSetBuilder.cs | 2 +- .../EFCore.Specification.Tests.csproj | 19 + .../ModelBuilding/GiantModel.cs | 1 - .../ModelBuilding/GiantModel.tt | 0 .../ModelBuilderTest.ComplexType.cs} | 40 +- .../ModelBuilderTest.Generic.cs} | 180 +- .../ModelBuilderTest.Inheritance.cs} | 80 +- .../ModelBuilderTest.ManyToMany.cs} | 0 .../ModelBuilderTest.ManyToOne.cs} | 2 +- .../ModelBuilderTest.NonGeneric.cs} | 200 +- .../ModelBuilderTest.NonRelationship.cs} | 83 +- .../ModelBuilderTest.OneToMany.cs} | 0 .../ModelBuilderTest.OneToOne.cs} | 0 .../ModelBuilderTest.OwnedTypes.cs} | 0 .../ModelBuilderTest.TestModel.cs} | 0 .../ModelBuilding/ModelBuilderTest.cs} | 1036 +--------- .../NonSharedModelTestBase.cs | 6 +- .../Scaffolding/CompiledModelTestBase.cs | 10 +- .../TestUtilities/ModelAsserter.cs | 1117 +++++++++++ .../TestUtilities/TestHelpers.cs | 15 +- .../TestValueConverterComparer.cs | 26 + .../SqlServerModelBuilderGenericTest.cs | 56 +- .../SqlServerModelBuilderNonGenericTest.cs | 98 + .../SqlServerModelBuilderTestBase.cs | 109 +- .../SqlServerTestModelBuilderExtensions.cs | 0 .../Query/QueryBugsTest.cs | 12 +- .../BigModel/DbContextModelBuilder.cs | 17 +- .../Baselines/Tpc/DependentBaseEntityType.cs | 1 + .../Baselines/Tpc/PrincipalBaseEntityType.cs | 1 + ...lServerValueGenerationScenariosTestBase.cs | 10 +- .../ModelCodeGeneratorTestBase.cs | 19 +- .../SqlServerModelBuilderNonGenericTest.cs | 114 -- .../SqliteModelBuilderGenericTest.cs | 106 + .../SqliteModelBuilderTestBase.cs | 85 + .../BigModel/DbContextModelBuilder.cs | 17 +- test/EFCore.Tests/EFCore.Tests.csproj | 24 - .../IEntityTypeConfigurationTest.cs | 2 +- .../Conventions/ConventionSetBuilderTests.cs | 25 + 82 files changed, 4387 insertions(+), 2605 deletions(-) rename test/{EFCore.Cosmos.Tests => EFCore.Cosmos.FunctionalTests}/ModelBuilding/CosmosModelBuilderGenericTest.cs (79%) rename test/{EFCore.Cosmos.Tests => EFCore.Cosmos.FunctionalTests}/ModelBuilding/CosmosTestModelBuilderExtensions.cs (100%) create mode 100644 test/EFCore.Cosmos.FunctionalTests/TestUtilities/CosmosModelAsserter.cs rename test/{EFCore.Tests/ModelBuilding/ModelBuilderAssemblyScanTest.cs => EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderAssemblyScanTest.cs} (97%) rename test/{EFCore.Tests/ModelBuilding/ModelBuilderGenericRelationshipStringTest.cs => EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderGenericRelationshipStringTest.cs} (88%) rename test/{EFCore.Tests/ModelBuilding/ModelBuilderGenericRelationshipTypeTest.cs => EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderGenericRelationshipTypeTest.cs} (94%) rename test/{EFCore.InMemory.Tests => EFCore.InMemory.FunctionalTests}/ModelBuilding/InMemoryModelBuilderGenericTest.cs (68%) rename test/{EFCore.Tests/ModelBuilding/ModelBuilderNonGenericStringTest.cs => EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderNonGenericStringTest.cs} (89%) create mode 100644 test/EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderNonGenericTest.cs rename test/{EFCore.Tests/ModelBuilding/ModelBuilderNonGenericUnqualifiedStringTest.cs => EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderNonGenericUnqualifiedStringTest.cs} (94%) create mode 100644 test/EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderTest.cs rename test/{EFCore.Tests => EFCore.InMemory.FunctionalTests}/ModelBuilding/PropertyBagEntityTypeTest.cs (100%) rename test/{EFCore.Relational.Tests => EFCore.Relational.Specification.Tests}/ModelBuilding/RelationalModelBuilderTest.cs (96%) rename test/{EFCore.Relational.Tests => EFCore.Relational.Specification.Tests}/ModelBuilding/RelationalTestModelBuilderExtensions.cs (100%) create mode 100644 test/EFCore.Relational.Specification.Tests/TestUtilities/RelationalModelAsserter.cs delete mode 100644 test/EFCore.Relational.Tests/TestUtilities/TestDbFunctions.cs rename test/{EFCore.Tests => EFCore.Specification.Tests}/ModelBuilding/GiantModel.cs (99%) rename test/{EFCore.Tests => EFCore.Specification.Tests}/ModelBuilding/GiantModel.tt (100%) rename test/{EFCore.Tests/ModelBuilding/ComplexTypeTestBase.cs => EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.ComplexType.cs} (98%) rename test/{EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs => EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.Generic.cs} (93%) rename test/{EFCore.Tests/ModelBuilding/InheritanceTestBase.cs => EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.Inheritance.cs} (94%) rename test/{EFCore.Tests/ModelBuilding/ManyToManyTestBase.cs => EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.ManyToMany.cs} (100%) rename test/{EFCore.Tests/ModelBuilding/ManyToOneTestBase.cs => EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.ManyToOne.cs} (99%) rename test/{EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs => EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.NonGeneric.cs} (92%) rename test/{EFCore.Tests/ModelBuilding/NonRelationshipTestBase.cs => EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.NonRelationship.cs} (97%) rename test/{EFCore.Tests/ModelBuilding/OneToManyTestBase.cs => EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.OneToMany.cs} (100%) rename test/{EFCore.Tests/ModelBuilding/OneToOneTestBase.cs => EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.OneToOne.cs} (100%) rename test/{EFCore.Tests/ModelBuilding/OwnedTypesTestBase.cs => EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.OwnedTypes.cs} (100%) rename test/{EFCore.Tests/ModelBuilding/TestModel.cs => EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.TestModel.cs} (100%) rename test/{EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs => EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.cs} (50%) create mode 100644 test/EFCore.Specification.Tests/TestUtilities/ModelAsserter.cs create mode 100644 test/EFCore.Specification.Tests/TestUtilities/TestValueConverterComparer.cs rename test/{EFCore.SqlServer.Tests => EFCore.SqlServer.FunctionalTests}/ModelBuilding/SqlServerModelBuilderGenericTest.cs (51%) create mode 100644 test/EFCore.SqlServer.FunctionalTests/ModelBuilding/SqlServerModelBuilderNonGenericTest.cs rename test/{EFCore.SqlServer.Tests => EFCore.SqlServer.FunctionalTests}/ModelBuilding/SqlServerModelBuilderTestBase.cs (94%) rename test/{EFCore.SqlServer.Tests => EFCore.SqlServer.FunctionalTests}/ModelBuilding/SqlServerTestModelBuilderExtensions.cs (100%) delete mode 100644 test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderNonGenericTest.cs create mode 100644 test/EFCore.Sqlite.FunctionalTests/ModelBuilding/SqliteModelBuilderGenericTest.cs create mode 100644 test/EFCore.Sqlite.FunctionalTests/ModelBuilding/SqliteModelBuilderTestBase.cs rename test/EFCore.Tests/{ModelBuilding => }/IEntityTypeConfigurationTest.cs (98%) diff --git a/src/EFCore.Design/Migrations/Internal/SnapshotModelProcessor.cs b/src/EFCore.Design/Migrations/Internal/SnapshotModelProcessor.cs index 75415561617..d5beace4bb6 100644 --- a/src/EFCore.Design/Migrations/Internal/SnapshotModelProcessor.cs +++ b/src/EFCore.Design/Migrations/Internal/SnapshotModelProcessor.cs @@ -33,7 +33,8 @@ public SnapshotModelProcessor( _relationalNames = new HashSet( typeof(RelationalAnnotationNames) .GetRuntimeFields() - .Where(p => p.Name != nameof(RelationalAnnotationNames.Prefix)) + .Where(p => p.Name != nameof(RelationalAnnotationNames.Prefix) + && p.Name != nameof(RelationalAnnotationNames.AllNames)) .Select(p => (string)p.GetValue(null)!) .Where(v => v.IndexOf(':') > 0) .Select(v => v[(RelationalAnnotationNames.Prefix.Length - 1)..])); diff --git a/src/EFCore.Relational/Design/Internal/RelationalCSharpRuntimeAnnotationCodeGenerator.cs b/src/EFCore.Relational/Design/Internal/RelationalCSharpRuntimeAnnotationCodeGenerator.cs index 92e6893d092..bd763e8a2f4 100644 --- a/src/EFCore.Relational/Design/Internal/RelationalCSharpRuntimeAnnotationCodeGenerator.cs +++ b/src/EFCore.Relational/Design/Internal/RelationalCSharpRuntimeAnnotationCodeGenerator.cs @@ -192,7 +192,7 @@ void CreateMappings( } // All the mappings below are added in a way that preserves the order - foreach (var mapping in typeBase.GetDefaultMappings()) + if (typeBase.GetDefaultMappings().Any()) { var tableMappingsVariable = code.Identifier("defaultTableMappings", parameters.ScopeVariables, capitalize: false); mainBuilder @@ -200,7 +200,10 @@ void CreateMappings( .AppendLine($"var {tableMappingsVariable} = new List>();") .Append($"{typeBaseVariable}.SetRuntimeAnnotation(") .AppendLine($"{code.Literal(RelationalAnnotationNames.DefaultMappings)}, {tableMappingsVariable});"); - Create(mapping, tableMappingsVariable, metadataVariables, parameters); + foreach (var mapping in typeBase.GetDefaultMappings()) + { + Create(mapping, tableMappingsVariable, metadataVariables, parameters); + } } if (typeBase.GetTableMappings().Any()) @@ -2090,8 +2093,10 @@ public override void Generate(IForeignKey foreignKey, CSharpRuntimeAnnotationCod /// public override void Generate(IIndex index, CSharpRuntimeAnnotationCodeGeneratorParameters parameters) { - var annotations = parameters.Annotations; - annotations.Remove(parameters.IsRuntime ? RelationalAnnotationNames.TableIndexMappings : RelationalAnnotationNames.Filter); + if (parameters.IsRuntime) + { + parameters.Annotations.Remove(RelationalAnnotationNames.TableIndexMappings); + } base.Generate(index, parameters); } diff --git a/src/EFCore.Relational/Metadata/Internal/ColumnBase.cs b/src/EFCore.Relational/Metadata/Internal/ColumnBase.cs index 7b834b380fc..faf668fc847 100644 --- a/src/EFCore.Relational/Metadata/Internal/ColumnBase.cs +++ b/src/EFCore.Relational/Metadata/Internal/ColumnBase.cs @@ -144,6 +144,15 @@ public virtual bool AddPropertyMapping(TColumnMappingBase columnMapping) return true; } + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public virtual void RemovePropertyMapping(TColumnMappingBase columnMapping) + => PropertyMappings.RemoveAt(PropertyMappings.IndexOf(columnMapping, ColumnMappingBaseComparer.Instance)); + /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in diff --git a/src/EFCore.Relational/Metadata/Internal/RelationalModel.cs b/src/EFCore.Relational/Metadata/Internal/RelationalModel.cs index b7f13f63b9f..9fa208ab0c3 100644 --- a/src/EFCore.Relational/Metadata/Internal/RelationalModel.cs +++ b/src/EFCore.Relational/Metadata/Internal/RelationalModel.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Data; using System.Text.Json; namespace Microsoft.EntityFrameworkCore.Metadata.Internal; @@ -1435,11 +1436,11 @@ private static void PopulateRowInternalForeignKeys(TableBase tab { TableMappingBase? mainMapping = null; var mappedEntityTypes = new HashSet(); - foreach (TableMappingBase entityTypeMapping in table.EntityTypeMappings) + foreach (TableMappingBase entityTypeMapping in table.EntityTypeMappings.ToList()) { if (table.EntityTypeMappings.Count > 1) { - entityTypeMapping.IsSharedTablePrincipal = false; + entityTypeMapping.SetIsSharedTablePrincipal(false); } var entityType = (IEntityType)entityTypeMapping.TypeBase; @@ -1489,10 +1490,7 @@ private static void PopulateRowInternalForeignKeys(TableBase tab if (table.EntityTypeMappings.Count > 1) { - // Re-add the mapping to update the order - mainMapping.Table.EntityTypeMappings.Remove(mainMapping); - mainMapping.IsSharedTablePrincipal = true; - mainMapping.Table.EntityTypeMappings.Add(mainMapping); + mainMapping.SetIsSharedTablePrincipal(true); } var referencingInternalForeignKeyMap = table.ReferencingRowInternalForeignKeys; diff --git a/src/EFCore.Relational/Metadata/Internal/TableMapping.cs b/src/EFCore.Relational/Metadata/Internal/TableMapping.cs index 7eb3dbe1fc3..e6f772aa6ca 100644 --- a/src/EFCore.Relational/Metadata/Internal/TableMapping.cs +++ b/src/EFCore.Relational/Metadata/Internal/TableMapping.cs @@ -58,6 +58,46 @@ public TableMapping( /// public virtual IStoredProcedureMapping? UpdateStoredProcedureMapping { get; set; } + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public override void SetIsSharedTablePrincipal(bool isSharedTablePrincipal) + { + if (IsSharedTablePrincipal == isSharedTablePrincipal) + { + return; + } + + ((Table)Table).EntityTypeMappings.Remove(this); + + var removedColumnMappings = new List(); + foreach (ColumnMapping columnMapping in ((ITableMapping)this).ColumnMappings) + { + ((Column)columnMapping.Column).RemovePropertyMapping(columnMapping); + var columnMappings = (SortedSet)columnMapping.Property.FindRuntimeAnnotationValue( + RelationalAnnotationNames.TableColumnMappings)!; + columnMappings.Remove(columnMapping); + + removedColumnMappings.Add(columnMapping); + } + + IsSharedTablePrincipal = isSharedTablePrincipal; + + // Re-add the mappings to update the order + ((Table)Table).EntityTypeMappings.Add(this); + + foreach (var columnMapping in removedColumnMappings) + { + ((Column)columnMapping.Column).AddPropertyMapping(columnMapping); + var columnMappings = (SortedSet)columnMapping.Property.FindRuntimeAnnotationValue( + RelationalAnnotationNames.TableColumnMappings)!; + columnMappings.Add(columnMapping); + } + } + /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in diff --git a/src/EFCore.Relational/Metadata/Internal/TableMappingBase.cs b/src/EFCore.Relational/Metadata/Internal/TableMappingBase.cs index 27fd74425da..0194b642339 100644 --- a/src/EFCore.Relational/Metadata/Internal/TableMappingBase.cs +++ b/src/EFCore.Relational/Metadata/Internal/TableMappingBase.cs @@ -83,7 +83,16 @@ public virtual bool AddColumnMapping(TColumnMapping columnMapping) public virtual bool? IsSharedTablePrincipal { get; set; } /// - public virtual bool? IsSplitEntityTypePrincipal { get; set; } + public virtual bool? IsSplitEntityTypePrincipal { get; init; } + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public virtual void SetIsSharedTablePrincipal(bool isSharedTablePrincipal) + => throw new NotImplementedException(); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to diff --git a/src/EFCore.Relational/Metadata/Internal/ViewMapping.cs b/src/EFCore.Relational/Metadata/Internal/ViewMapping.cs index 0d92331d077..598a1a06765 100644 --- a/src/EFCore.Relational/Metadata/Internal/ViewMapping.cs +++ b/src/EFCore.Relational/Metadata/Internal/ViewMapping.cs @@ -29,6 +29,46 @@ public ViewMapping( public virtual IView View => (IView)base.Table; + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public override void SetIsSharedTablePrincipal(bool isSharedTablePrincipal) + { + if (IsSharedTablePrincipal == isSharedTablePrincipal) + { + return; + } + + ((View)View).EntityTypeMappings.Remove(this); + + var removedColumnMappings = new List(); + foreach (ViewColumnMapping columnMapping in ((IViewMapping)this).ColumnMappings) + { + ((ViewColumn)columnMapping.Column).RemovePropertyMapping(columnMapping); + var columnMappings = (SortedSet)columnMapping.Property.FindRuntimeAnnotationValue( + RelationalAnnotationNames.ViewColumnMappings)!; + columnMappings.Remove(columnMapping); + + removedColumnMappings.Add(columnMapping); + } + + IsSharedTablePrincipal = isSharedTablePrincipal; + + // Re-add the mappings to update the order + ((View)View).EntityTypeMappings.Add(this); + + foreach (var columnMapping in removedColumnMappings) + { + ((ViewColumn)columnMapping.Column).AddPropertyMapping(columnMapping); + var columnMappings = (SortedSet)columnMapping.Property.FindRuntimeAnnotationValue( + RelationalAnnotationNames.ViewColumnMappings)!; + columnMappings.Add(columnMapping); + } + } + /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in diff --git a/src/EFCore.Relational/Metadata/RelationalAnnotationNames.cs b/src/EFCore.Relational/Metadata/RelationalAnnotationNames.cs index 2aee5c9cef4..7d9f62d9ffe 100644 --- a/src/EFCore.Relational/Metadata/RelationalAnnotationNames.cs +++ b/src/EFCore.Relational/Metadata/RelationalAnnotationNames.cs @@ -334,4 +334,78 @@ public static class RelationalAnnotationNames /// The name for store (database) type annotations. /// public const string StoreType = Prefix + "StoreType"; + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public static readonly ISet AllNames = new HashSet + { + ColumnName, + ColumnOrder, + ColumnType, + DefaultValueSql, + ComputedColumnSql, + IsStored, + DefaultValue, + TableName, + Schema, + ViewName, + ViewSchema, + FunctionName, + DeleteStoredProcedure, + InsertStoredProcedure, + UpdateStoredProcedure, + SqlQuery, + Comment, + Collation, + DefaultSchema, + Name, + #pragma warning disable CS0618 // Type or member is obsolete + SequencePrefix, + #pragma warning restore CS0618 // Type or member is obsolete + Sequences, + CheckConstraints, + Filter, + DbFunctions, + MaxIdentifierLength, + IsFixedLength, + ViewDefinitionSql, + IsTableExcludedFromMigrations, + MappingStrategy, + RelationalModel, + DefaultMappings, + DefaultColumnMappings, + TableMappings, + TableColumnMappings, + ViewMappings, + ViewColumnMappings, + FunctionMappings, + FunctionColumnMappings, + InsertStoredProcedureMappings, + InsertStoredProcedureResultColumnMappings, + InsertStoredProcedureParameterMappings, + DeleteStoredProcedureMappings, + DeleteStoredProcedureParameterMappings, + UpdateStoredProcedureMappings, + UpdateStoredProcedureResultColumnMappings, + UpdateStoredProcedureParameterMappings, + SqlQueryMappings, + SqlQueryColumnMappings, + ForeignKeyMappings, + TableIndexMappings, + UniqueConstraintMappings, + MappingFragments, + RelationalOverrides, + ModelDependencies, + FieldValueGetter, + ContainerColumnName, + #pragma warning disable CS0618 // Type or member is obsolete + ContainerColumnTypeMapping, + #pragma warning restore CS0618 // Type or member is obsolete + JsonPropertyName, + StoreType + }; } diff --git a/test/EFCore.Cosmos.FunctionalTests/EFCore.Cosmos.FunctionalTests.csproj b/test/EFCore.Cosmos.FunctionalTests/EFCore.Cosmos.FunctionalTests.csproj index de07aa034e6..c32b3fd6b15 100644 --- a/test/EFCore.Cosmos.FunctionalTests/EFCore.Cosmos.FunctionalTests.csproj +++ b/test/EFCore.Cosmos.FunctionalTests/EFCore.Cosmos.FunctionalTests.csproj @@ -47,7 +47,7 @@ - + PreserveNewest diff --git a/test/EFCore.Cosmos.Tests/ModelBuilding/CosmosModelBuilderGenericTest.cs b/test/EFCore.Cosmos.FunctionalTests/ModelBuilding/CosmosModelBuilderGenericTest.cs similarity index 79% rename from test/EFCore.Cosmos.Tests/ModelBuilding/CosmosModelBuilderGenericTest.cs rename to test/EFCore.Cosmos.FunctionalTests/ModelBuilding/CosmosModelBuilderGenericTest.cs index 0dd3ed80234..a527ee2af5e 100644 --- a/test/EFCore.Cosmos.Tests/ModelBuilding/CosmosModelBuilderGenericTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/ModelBuilding/CosmosModelBuilderGenericTest.cs @@ -1,15 +1,17 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#nullable enable + using Microsoft.EntityFrameworkCore.Cosmos.Internal; using Xunit.Sdk; // ReSharper disable InconsistentNaming namespace Microsoft.EntityFrameworkCore.ModelBuilding; -public class CosmosModelBuilderGenericTest : ModelBuilderGenericTest +public class CosmosModelBuilderGenericTest : ModelBuilderTest { - public class CosmosGenericNonRelationship : GenericNonRelationship, IClassFixture + public class CosmosGenericNonRelationship : NonRelationshipTestBase, IClassFixture { public CosmosGenericNonRelationship(CosmosModelBuilderFixture fixture) : base(fixture) @@ -20,193 +22,205 @@ public override void Can_set_composite_key_for_primitive_collection_on_an_entity => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(EntityWithFields), "CollectionCompanyId"), Assert.Throws( - () => base.Can_set_composite_key_for_primitive_collection_on_an_entity_with_fields()).Message); + base.Can_set_composite_key_for_primitive_collection_on_an_entity_with_fields).Message); + + public override void Can_set_alternate_key_for_primitive_collection_on_an_entity_with_fields() + => Assert.Equal( + CosmosStrings.PrimitiveCollectionsNotSupported(nameof(EntityWithFields), "CollectionCompanyId"), + Assert.Throws( + base.Can_set_alternate_key_for_primitive_collection_on_an_entity_with_fields).Message); + + public override void Can_call_PrimitiveCollection_on_an_entity_with_fields() + => Assert.Equal( + CosmosStrings.PrimitiveCollectionsNotSupported(nameof(EntityWithFields), "CollectionId"), + Assert.Throws( + base.Can_call_PrimitiveCollection_on_an_entity_with_fields).Message); public override void Access_mode_can_be_overridden_at_entity_and_primitive_collection_levels() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Down"), Assert.Throws( - () => base.Access_mode_can_be_overridden_at_entity_and_primitive_collection_levels()).Message); + base.Access_mode_can_be_overridden_at_entity_and_primitive_collection_levels).Message); public override void Can_set_custom_value_generator_for_primitive_collections() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Bottom"), Assert.Throws( - () => base.Can_set_custom_value_generator_for_primitive_collections()).Message); + base.Can_set_custom_value_generator_for_primitive_collections).Message); public override void Can_set_element_type_annotation() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(Customer), "Notes"), Assert.Throws( - () => base.Can_set_element_type_annotation()).Message); + base.Can_set_element_type_annotation).Message); public override void Can_set_max_length_for_primitive_collections() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Bottom"), Assert.Throws( - () => base.Can_set_max_length_for_primitive_collections()).Message); + base.Can_set_max_length_for_primitive_collections).Message); public override void Can_set_primitive_collection_annotation() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(Customer), "Notes"), Assert.Throws( - () => base.Can_set_primitive_collection_annotation()).Message); + base.Can_set_primitive_collection_annotation).Message); public override void Can_set_primitive_collection_annotation_by_type() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(Customer), "Notes"), Assert.Throws( - () => base.Can_set_primitive_collection_annotation_by_type()).Message); + base.Can_set_primitive_collection_annotation_by_type).Message); public override void Can_set_primitive_collection_annotation_when_no_clr_property() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(Customer), "Notes"), Assert.Throws( - () => base.Can_set_primitive_collection_annotation_when_no_clr_property()).Message); + base.Can_set_primitive_collection_annotation_when_no_clr_property).Message); public override void Can_set_sentinel_for_primitive_collections() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Bottom"), Assert.Throws( - () => base.Can_set_sentinel_for_primitive_collections()).Message); + base.Can_set_sentinel_for_primitive_collections).Message); public override void Can_set_unicode_for_primitive_collections() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Bottom"), Assert.Throws( - () => base.Can_set_unicode_for_primitive_collections()).Message); + base.Can_set_unicode_for_primitive_collections).Message); public override void Element_types_are_nullable_by_default_if_the_type_is_nullable() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), Assert.Throws( - () => base.Element_types_are_nullable_by_default_if_the_type_is_nullable()).Message); + base.Element_types_are_nullable_by_default_if_the_type_is_nullable).Message); public override void Element_types_can_be_made_required() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), Assert.Throws( - () => base.Element_types_can_be_made_required()).Message); + base.Element_types_can_be_made_required).Message); public override void Element_types_can_have_custom_type_value_converter_type_set() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), Assert.Throws( - () => base.Element_types_can_have_custom_type_value_converter_type_set()).Message); + base.Element_types_can_have_custom_type_value_converter_type_set).Message); public override void Element_types_can_have_max_length() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), Assert.Throws( - () => base.Element_types_can_have_max_length()).Message); + base.Element_types_can_have_max_length).Message); public override void Element_types_can_have_non_generic_value_converter_set() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), Assert.Throws( - () => base.Element_types_can_have_non_generic_value_converter_set()).Message); + base.Element_types_can_have_non_generic_value_converter_set).Message); public override void Element_types_can_have_precision_and_scale() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), Assert.Throws( - () => base.Element_types_can_have_precision_and_scale()).Message); + base.Element_types_can_have_precision_and_scale).Message); public override void Element_types_can_have_provider_type_set() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), Assert.Throws( - () => base.Element_types_can_have_provider_type_set()).Message); + base.Element_types_can_have_provider_type_set).Message); public override void Element_types_can_have_unicode_set() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), Assert.Throws( - () => base.Element_types_can_have_unicode_set()).Message); + base.Element_types_can_have_unicode_set).Message); public override void Element_types_have_default_precision_and_scale() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), Assert.Throws( - () => base.Element_types_have_default_precision_and_scale()).Message); + base.Element_types_have_default_precision_and_scale).Message); public override void Element_types_have_default_unicode() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), Assert.Throws( - () => base.Element_types_have_default_unicode()).Message); + base.Element_types_have_default_unicode).Message); public override void Element_types_have_no_max_length_by_default() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), Assert.Throws( - () => base.Element_types_have_no_max_length_by_default()).Message); + base.Element_types_have_no_max_length_by_default).Message); public override void Primitive_collections_are_required_by_default_only_if_CLR_type_is_nullable() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), Assert.Throws( - () => base.Primitive_collections_are_required_by_default_only_if_CLR_type_is_nullable()).Message); + base.Primitive_collections_are_required_by_default_only_if_CLR_type_is_nullable).Message); public override void Primitive_collections_can_be_made_optional() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), Assert.Throws( - () => base.Primitive_collections_can_be_made_optional()).Message); + base.Primitive_collections_can_be_made_optional).Message); public override void Primitive_collections_can_be_made_required() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), Assert.Throws( - () => base.Primitive_collections_can_be_made_required()).Message); + base.Primitive_collections_can_be_made_required).Message); public override void Primitive_collections_can_be_set_to_generate_values_on_Add() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Bottom"), Assert.Throws( - () => base.Primitive_collections_can_be_set_to_generate_values_on_Add()).Message); + base.Primitive_collections_can_be_set_to_generate_values_on_Add).Message); public override void Primitive_collections_can_have_access_mode_set() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), Assert.Throws( - () => base.Primitive_collections_can_have_access_mode_set()).Message); + base.Primitive_collections_can_have_access_mode_set).Message); public override void Primitive_collections_can_have_field_set() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Down"), Assert.Throws( - () => base.Primitive_collections_can_have_field_set()).Message); + base.Primitive_collections_can_have_field_set).Message); public override void Primitive_collections_can_have_value_converter_set() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), Assert.Throws( - () => base.Primitive_collections_can_have_value_converter_set()).Message); + base.Primitive_collections_can_have_value_converter_set).Message); public override void Primitive_collections_specified_by_string_are_shadow_properties_unless_already_known_to_be_CLR_properties() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), Assert.Throws( - () => base.Primitive_collections_specified_by_string_are_shadow_properties_unless_already_known_to_be_CLR_properties()).Message); + base.Primitive_collections_specified_by_string_are_shadow_properties_unless_already_known_to_be_CLR_properties).Message); public override void Value_converter_type_on_primitive_collection_is_checked() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Up"), Assert.Throws( - () => base.Value_converter_type_on_primitive_collection_is_checked()).Message); + base.Value_converter_type_on_primitive_collection_is_checked).Message); public override void Properties_can_set_row_version() => Assert.Equal( CosmosStrings.NonETagConcurrencyToken(nameof(Quarks), "Charm"), Assert.Throws( - () => base.Properties_can_set_row_version()).Message); + base.Properties_can_set_row_version).Message); public override void Properties_can_be_made_concurrency_tokens() => Assert.Equal( CosmosStrings.NonETagConcurrencyToken(nameof(Quarks), "Charm"), Assert.Throws( - () => base.Properties_can_be_made_concurrency_tokens()).Message); + base.Properties_can_be_made_concurrency_tokens).Message); public override void Properties_can_have_provider_type_set_for_type() { @@ -223,12 +237,12 @@ public override void Properties_can_have_provider_type_set_for_type() }); var model = modelBuilder.FinalizeModel(); - var entityType = (IReadOnlyEntityType)model.FindEntityType(typeof(Quarks)); + var entityType = (IReadOnlyEntityType)model.FindEntityType(typeof(Quarks))!; - Assert.Null(entityType.FindProperty("Up").GetProviderClrType()); - Assert.Same(typeof(byte[]), entityType.FindProperty("Down").GetProviderClrType()); - Assert.Null(entityType.FindProperty("Charm").GetProviderClrType()); - Assert.Same(typeof(byte[]), entityType.FindProperty("Strange").GetProviderClrType()); + Assert.Null(entityType.FindProperty("Up")!.GetProviderClrType()); + Assert.Same(typeof(byte[]), entityType.FindProperty("Down")!.GetProviderClrType()); + Assert.Null(entityType.FindProperty("Charm")!.GetProviderClrType()); + Assert.Same(typeof(byte[]), entityType.FindProperty("Strange")!.GetProviderClrType()); } public override void Properties_can_be_set_to_generate_values_on_Add() @@ -248,14 +262,14 @@ public override void Properties_can_be_set_to_generate_values_on_Add() }); var model = modelBuilder.FinalizeModel(); - var entityType = model.FindEntityType(typeof(Quarks)); - Assert.Equal(ValueGenerated.Never, entityType.FindProperty(Customer.IdProperty.Name).ValueGenerated); - Assert.Equal(ValueGenerated.OnAddOrUpdate, entityType.FindProperty("Up").ValueGenerated); - Assert.Equal(ValueGenerated.Never, entityType.FindProperty("Down").ValueGenerated); - Assert.Equal(ValueGenerated.OnUpdateSometimes, entityType.FindProperty("Charm").ValueGenerated); - Assert.Equal(ValueGenerated.Never, entityType.FindProperty("Strange").ValueGenerated); - Assert.Equal(ValueGenerated.OnAddOrUpdate, entityType.FindProperty("Top").ValueGenerated); - Assert.Equal(ValueGenerated.OnUpdate, entityType.FindProperty("Bottom").ValueGenerated); + var entityType = model.FindEntityType(typeof(Quarks))!; + Assert.Equal(ValueGenerated.Never, entityType.FindProperty(Customer.IdProperty.Name)!.ValueGenerated); + Assert.Equal(ValueGenerated.OnAddOrUpdate, entityType.FindProperty("Up")!.ValueGenerated); + Assert.Equal(ValueGenerated.Never, entityType.FindProperty("Down")!.ValueGenerated); + Assert.Equal(ValueGenerated.OnUpdateSometimes, entityType.FindProperty("Charm")!.ValueGenerated); + Assert.Equal(ValueGenerated.Never, entityType.FindProperty("Strange")!.ValueGenerated); + Assert.Equal(ValueGenerated.OnAddOrUpdate, entityType.FindProperty("Top")!.ValueGenerated); + Assert.Equal(ValueGenerated.OnUpdate, entityType.FindProperty("Bottom")!.ValueGenerated); } [ConditionalFact] @@ -271,16 +285,16 @@ public virtual void Partition_key_is_added_to_the_keys() var model = modelBuilder.FinalizeModel(); - var entity = model.FindEntityType(typeof(Customer)); + var entity = model.FindEntityType(typeof(Customer))!; Assert.Equal( new[] { nameof(Customer.Id), nameof(Customer.AlternateKey) }, - entity.FindPrimaryKey().Properties.Select(p => p.Name)); + entity.FindPrimaryKey()!.Properties.Select(p => p.Name)); Assert.Equal( new[] { StoreKeyConvention.DefaultIdPropertyName, nameof(Customer.AlternateKey) }, entity.GetKeys().First(k => k != entity.FindPrimaryKey()).Properties.Select(p => p.Name)); - var idProperty = entity.FindProperty(StoreKeyConvention.DefaultIdPropertyName); + var idProperty = entity.FindProperty(StoreKeyConvention.DefaultIdPropertyName)!; Assert.Single(idProperty.GetContainingKeys()); Assert.NotNull(idProperty.GetValueGeneratorFactory()); } @@ -299,11 +313,11 @@ public virtual void Partition_key_is_added_to_the_alternate_key_if_primary_key_c var model = modelBuilder.FinalizeModel(); - var entity = model.FindEntityType(typeof(Customer)); + var entity = model.FindEntityType(typeof(Customer))!; Assert.Equal( new[] { StoreKeyConvention.DefaultIdPropertyName }, - entity.FindPrimaryKey().Properties.Select(p => p.Name)); + entity.FindPrimaryKey()!.Properties.Select(p => p.Name)); Assert.Equal( new[] { StoreKeyConvention.DefaultIdPropertyName, nameof(Customer.AlternateKey) }, entity.GetKeys().First(k => k != entity.FindPrimaryKey()).Properties.Select(p => p.Name)); @@ -323,7 +337,7 @@ public virtual void No_id_property_created_if_another_property_mapped_to_id() var model = modelBuilder.FinalizeModel(); - var entity = model.FindEntityType(typeof(Customer)); + var entity = model.FindEntityType(typeof(Customer))!; Assert.Null(entity.FindProperty(StoreKeyConvention.DefaultIdPropertyName)); Assert.Single(entity.GetKeys().Where(k => k != entity.FindPrimaryKey())); @@ -372,14 +386,14 @@ public virtual void No_alternate_key_is_created_if_primary_key_contains_id() var model = modelBuilder.FinalizeModel(); - var entity = model.FindEntityType(typeof(Customer)); + var entity = model.FindEntityType(typeof(Customer))!; Assert.Equal( new[] { StoreKeyConvention.DefaultIdPropertyName }, - entity.FindPrimaryKey().Properties.Select(p => p.Name)); + entity.FindPrimaryKey()!.Properties.Select(p => p.Name)); Assert.Empty(entity.GetKeys().Where(k => k != entity.FindPrimaryKey())); - var idProperty = entity.FindProperty(StoreKeyConvention.DefaultIdPropertyName); + var idProperty = entity.FindProperty(StoreKeyConvention.DefaultIdPropertyName)!; Assert.Single(idProperty.GetContainingKeys()); Assert.Null(idProperty.GetValueGeneratorFactory()); } @@ -398,11 +412,11 @@ public virtual void No_alternate_key_is_created_if_primary_key_contains_id_and_p var model = modelBuilder.FinalizeModel(); - var entity = model.FindEntityType(typeof(Customer)); + var entity = model.FindEntityType(typeof(Customer))!; Assert.Equal( new[] { nameof(Customer.AlternateKey), StoreKeyConvention.DefaultIdPropertyName }, - entity.FindPrimaryKey().Properties.Select(p => p.Name)); + entity.FindPrimaryKey()!.Properties.Select(p => p.Name)); Assert.Empty(entity.GetKeys().Where(k => k != entity.FindPrimaryKey())); } @@ -420,11 +434,11 @@ public virtual void No_alternate_key_is_created_if_id_is_partition_key() var model = modelBuilder.FinalizeModel(); - var entity = model.FindEntityType(typeof(Customer)); + var entity = model.FindEntityType(typeof(Customer))!; Assert.Equal( new[] { nameof(Customer.AlternateKey) }, - entity.FindPrimaryKey().Properties.Select(p => p.Name)); + entity.FindPrimaryKey()!.Properties.Select(p => p.Name)); Assert.Empty(entity.GetKeys().Where(k => k != entity.FindPrimaryKey())); } @@ -432,13 +446,13 @@ public override void Primitive_collections_can_be_made_concurrency_tokens() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), Assert.Throws( - () => base.Primitive_collections_can_be_made_concurrency_tokens()).Message); + base.Primitive_collections_can_be_made_concurrency_tokens).Message); - protected override TestModelBuilder CreateModelBuilder(Action configure = null) - => CreateTestModelBuilder(CosmosTestHelpers.Instance, configure); + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new GenericTestModelBuilder(Fixture, configure); } - public class CosmosGenericComplexType : GenericComplexType, IClassFixture + public class CosmosGenericComplexType : ComplexTypeTestBase, IClassFixture { public CosmosGenericComplexType(CosmosModelBuilderFixture fixture) : base(fixture) @@ -449,97 +463,97 @@ public override void Access_mode_can_be_overridden_at_entity_and_property_levels => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Down"), Assert.Throws( - () => base.Access_mode_can_be_overridden_at_entity_and_property_levels()).Message); + base.Access_mode_can_be_overridden_at_entity_and_property_levels).Message); public override void Can_add_shadow_primitive_collections_when_they_have_been_ignored() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(Customer), "Shadow"), Assert.Throws( - () => base.Can_add_shadow_primitive_collections_when_they_have_been_ignored()).Message); + base.Can_add_shadow_primitive_collections_when_they_have_been_ignored).Message); public override void Can_call_PrimitiveCollection_on_a_field() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(EntityWithFields), "CollectionId"), Assert.Throws( - () => base.Can_call_PrimitiveCollection_on_a_field()).Message); + base.Can_call_PrimitiveCollection_on_a_field).Message); public override void Can_set_custom_value_generator_for_primitive_collections() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Bottom"), Assert.Throws( - () => base.Can_set_custom_value_generator_for_primitive_collections()).Message); + base.Can_set_custom_value_generator_for_primitive_collections).Message); public override void Can_set_max_length_for_primitive_collections() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Bottom"), Assert.Throws( - () => base.Can_set_max_length_for_primitive_collections()).Message); + base.Can_set_max_length_for_primitive_collections).Message); public override void Can_set_primitive_collection_annotation_when_no_clr_property() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(Customer), "Ints"), Assert.Throws( - () => base.Can_set_primitive_collection_annotation_when_no_clr_property()).Message); + base.Can_set_primitive_collection_annotation_when_no_clr_property).Message); public override void Can_set_sentinel_for_primitive_collections() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Bottom"), Assert.Throws( - () => base.Can_set_sentinel_for_primitive_collections()).Message); + base.Can_set_sentinel_for_primitive_collections).Message); public override void Can_set_unicode_for_primitive_collections() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Bottom"), Assert.Throws( - () => base.Can_set_unicode_for_primitive_collections()).Message); + base.Can_set_unicode_for_primitive_collections).Message); public override void Primitive_collections_are_required_by_default_only_if_CLR_type_is_nullable() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), Assert.Throws( - () => base.Primitive_collections_are_required_by_default_only_if_CLR_type_is_nullable()).Message); + base.Primitive_collections_are_required_by_default_only_if_CLR_type_is_nullable).Message); public override void Primitive_collections_can_be_made_concurrency_tokens() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), Assert.Throws( - () => base.Primitive_collections_can_be_made_concurrency_tokens()).Message); + base.Primitive_collections_can_be_made_concurrency_tokens).Message); public override void Primitive_collections_can_be_made_optional() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), Assert.Throws( - () => base.Primitive_collections_can_be_made_optional()).Message); + base.Primitive_collections_can_be_made_optional).Message); public override void Primitive_collections_can_be_made_required() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), Assert.Throws( - () => base.Primitive_collections_can_be_made_required()).Message); + base.Primitive_collections_can_be_made_required).Message); public override void Primitive_collections_can_be_set_to_generate_values_on_Add() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Bottom"), Assert.Throws( - () => base.Primitive_collections_can_be_set_to_generate_values_on_Add()).Message); + base.Primitive_collections_can_be_set_to_generate_values_on_Add).Message); public override void Primitive_collections_can_have_field_set() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Down"), Assert.Throws( - () => base.Primitive_collections_can_have_field_set()).Message); + base.Primitive_collections_can_have_field_set).Message); public override void Primitive_collections_specified_by_string_are_shadow_properties_unless_already_known_to_be_CLR_properties() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), Assert.Throws( - () => base.Primitive_collections_specified_by_string_are_shadow_properties_unless_already_known_to_be_CLR_properties()).Message); + base.Primitive_collections_specified_by_string_are_shadow_properties_unless_already_known_to_be_CLR_properties).Message); public override void Properties_can_have_access_mode_set() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Down"), Assert.Throws( - () => base.Properties_can_have_access_mode_set()).Message); + base.Properties_can_have_access_mode_set).Message); public override void Can_set_complex_property_annotation() { @@ -555,7 +569,7 @@ public override void Can_set_complex_property_annotation() .Ignore(c => c.Orders); var model = modelBuilder.FinalizeModel(); - var complexProperty = model.FindEntityType(typeof(ComplexProperties)).GetComplexProperties().Single(); + var complexProperty = model.FindEntityType(typeof(ComplexProperties))!.GetComplexProperties().Single(); Assert.Equal("bar", complexProperty.ComplexType["foo"]); Assert.Equal("bar2", complexProperty["foo2"]); @@ -594,12 +608,12 @@ public override void Properties_can_have_provider_type_set_for_type() }); var model = modelBuilder.FinalizeModel(); - var complexType = model.FindEntityType(typeof(ComplexProperties)).GetComplexProperties().Single().ComplexType; + var complexType = model.FindEntityType(typeof(ComplexProperties))!.GetComplexProperties().Single().ComplexType; - Assert.Null(complexType.FindProperty("Up").GetProviderClrType()); - Assert.Same(typeof(byte[]), complexType.FindProperty("Down").GetProviderClrType()); - Assert.Null(complexType.FindProperty("Charm").GetProviderClrType()); - Assert.Same(typeof(byte[]), complexType.FindProperty("Strange").GetProviderClrType()); + Assert.Null(complexType.FindProperty("Up")!.GetProviderClrType()); + Assert.Same(typeof(byte[]), complexType.FindProperty("Down")!.GetProviderClrType()); + Assert.Null(complexType.FindProperty("Charm")!.GetProviderClrType()); + Assert.Same(typeof(byte[]), complexType.FindProperty("Strange")!.GetProviderClrType()); } [ConditionalFact] @@ -615,16 +629,16 @@ public virtual void Partition_key_is_added_to_the_keys() var model = modelBuilder.FinalizeModel(); - var entity = model.FindEntityType(typeof(Customer)); + var entity = model.FindEntityType(typeof(Customer))!; Assert.Equal( new[] { nameof(Customer.Id), nameof(Customer.AlternateKey) }, - entity.FindPrimaryKey().Properties.Select(p => p.Name)); + entity.FindPrimaryKey()!.Properties.Select(p => p.Name)); Assert.Equal( new[] { StoreKeyConvention.DefaultIdPropertyName, nameof(Customer.AlternateKey) }, entity.GetKeys().First(k => k != entity.FindPrimaryKey()).Properties.Select(p => p.Name)); - var idProperty = entity.FindProperty(StoreKeyConvention.DefaultIdPropertyName); + var idProperty = entity.FindProperty(StoreKeyConvention.DefaultIdPropertyName)!; Assert.Single(idProperty.GetContainingKeys()); Assert.NotNull(idProperty.GetValueGeneratorFactory()); } @@ -643,11 +657,11 @@ public virtual void Partition_key_is_added_to_the_alternate_key_if_primary_key_c var model = modelBuilder.FinalizeModel(); - var entity = model.FindEntityType(typeof(Customer)); + var entity = model.FindEntityType(typeof(Customer))!; Assert.Equal( new[] { StoreKeyConvention.DefaultIdPropertyName }, - entity.FindPrimaryKey().Properties.Select(p => p.Name)); + entity.FindPrimaryKey()!.Properties.Select(p => p.Name)); Assert.Equal( new[] { StoreKeyConvention.DefaultIdPropertyName, nameof(Customer.AlternateKey) }, entity.GetKeys().First(k => k != entity.FindPrimaryKey()).Properties.Select(p => p.Name)); @@ -667,7 +681,7 @@ public virtual void No_id_property_created_if_another_property_mapped_to_id() var model = modelBuilder.FinalizeModel(); - var entity = model.FindEntityType(typeof(Customer)); + var entity = model.FindEntityType(typeof(Customer))!; Assert.Null(entity.FindProperty(StoreKeyConvention.DefaultIdPropertyName)); Assert.Single(entity.GetKeys().Where(k => k != entity.FindPrimaryKey())); @@ -693,7 +707,7 @@ public virtual void No_id_property_created_if_another_property_mapped_to_id_in_p var model = modelBuilder.FinalizeModel(); - var entity = model.FindEntityType(typeof(Customer)); + var entity = model.FindEntityType(typeof(Customer))!; Assert.Null(entity.FindProperty(StoreKeyConvention.DefaultIdPropertyName)); Assert.Empty(entity.GetKeys().Where(k => k != entity.FindPrimaryKey())); @@ -716,14 +730,14 @@ public virtual void No_alternate_key_is_created_if_primary_key_contains_id() var model = modelBuilder.FinalizeModel(); - var entity = model.FindEntityType(typeof(Customer)); + var entity = model.FindEntityType(typeof(Customer))!; Assert.Equal( new[] { StoreKeyConvention.DefaultIdPropertyName }, - entity.FindPrimaryKey().Properties.Select(p => p.Name)); + entity.FindPrimaryKey()!.Properties.Select(p => p.Name)); Assert.Empty(entity.GetKeys().Where(k => k != entity.FindPrimaryKey())); - var idProperty = entity.FindProperty(StoreKeyConvention.DefaultIdPropertyName); + var idProperty = entity.FindProperty(StoreKeyConvention.DefaultIdPropertyName)!; Assert.Single(idProperty.GetContainingKeys()); Assert.Null(idProperty.GetValueGeneratorFactory()); } @@ -742,11 +756,11 @@ public virtual void No_alternate_key_is_created_if_primary_key_contains_id_and_p var model = modelBuilder.FinalizeModel(); - var entity = model.FindEntityType(typeof(Customer)); + var entity = model.FindEntityType(typeof(Customer))!; Assert.Equal( new[] { nameof(Customer.AlternateKey), StoreKeyConvention.DefaultIdPropertyName }, - entity.FindPrimaryKey().Properties.Select(p => p.Name)); + entity.FindPrimaryKey()!.Properties.Select(p => p.Name)); Assert.Empty(entity.GetKeys().Where(k => k != entity.FindPrimaryKey())); } @@ -764,19 +778,19 @@ public virtual void No_alternate_key_is_created_if_id_is_partition_key() var model = modelBuilder.FinalizeModel(); - var entity = model.FindEntityType(typeof(Customer)); + var entity = model.FindEntityType(typeof(Customer))!; Assert.Equal( new[] { nameof(Customer.AlternateKey) }, - entity.FindPrimaryKey().Properties.Select(p => p.Name)); + entity.FindPrimaryKey()!.Properties.Select(p => p.Name)); Assert.Empty(entity.GetKeys().Where(k => k != entity.FindPrimaryKey())); } - protected override TestModelBuilder CreateModelBuilder(Action configure = null) - => CreateTestModelBuilder(CosmosTestHelpers.Instance, configure); + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new GenericTestModelBuilder(Fixture, configure); } - public class CosmosGenericInheritance : GenericInheritance, IClassFixture + public class CosmosGenericInheritance : InheritanceTestBase, IClassFixture { public CosmosGenericInheritance(CosmosModelBuilderFixture fixture) : base(fixture) @@ -795,7 +809,7 @@ public override void Base_type_can_be_discovered_after_creating_foreign_keys_on_ foreach (var mutableEntityType in mutableEntityTypes) { - var mutableProperty = mutableEntityType.FindProperty(nameof(Q.ID)); + var mutableProperty = mutableEntityType.FindProperty(nameof(Q.ID))!; Assert.Equal(ValueGenerated.Never, mutableProperty.ValueGenerated); } @@ -804,13 +818,13 @@ public override void Base_type_can_be_discovered_after_creating_foreign_keys_on_ public override void Relationships_on_derived_types_are_discovered_first_if_base_is_one_sided() // Base discovered as owned => Assert.Throws( - () => base.Relationships_on_derived_types_are_discovered_first_if_base_is_one_sided()); + base.Relationships_on_derived_types_are_discovered_first_if_base_is_one_sided); - protected override TestModelBuilder CreateModelBuilder(Action configure = null) - => CreateTestModelBuilder(CosmosTestHelpers.Instance, configure); + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new GenericTestModelBuilder(Fixture, configure); } - public class CosmosGenericOneToMany : GenericOneToMany, IClassFixture + public class CosmosGenericOneToMany : OneToManyTestBase, IClassFixture { public CosmosGenericOneToMany(CosmosModelBuilderFixture fixture) : base(fixture) @@ -825,8 +839,8 @@ public override void Navigation_to_shared_type_is_not_discovered_by_convention() var model = modelBuilder.FinalizeModel(); - var principal = model.FindEntityType(typeof(CollectionNavigationToSharedType)); - var owned = principal.FindNavigation(nameof(CollectionNavigationToSharedType.Navigation)).TargetEntityType; + var principal = model.FindEntityType(typeof(CollectionNavigationToSharedType))!; + var owned = principal.FindNavigation(nameof(CollectionNavigationToSharedType.Navigation))!.TargetEntityType; Assert.True(owned.IsOwned()); Assert.True(owned.HasSharedClrType); Assert.Equal( @@ -834,22 +848,22 @@ public override void Navigation_to_shared_type_is_not_discovered_by_convention() owned.DisplayName()); } - protected override TestModelBuilder CreateModelBuilder(Action configure = null) - => CreateTestModelBuilder(CosmosTestHelpers.Instance, configure); + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new GenericTestModelBuilder(Fixture, configure); } - public class CosmosGenericManyToOne : GenericManyToOne, IClassFixture + public class CosmosGenericManyToOne : ManyToOneTestBase, IClassFixture { public CosmosGenericManyToOne(CosmosModelBuilderFixture fixture) : base(fixture) { } - protected override TestModelBuilder CreateModelBuilder(Action configure = null) - => CreateTestModelBuilder(CosmosTestHelpers.Instance, configure); + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new GenericTestModelBuilder(Fixture, configure); } - public class CosmosGenericOneToOne : GenericOneToOne, IClassFixture + public class CosmosGenericOneToOne : OneToOneTestBase, IClassFixture { public CosmosGenericOneToOne(CosmosModelBuilderFixture fixture) : base(fixture) @@ -864,8 +878,8 @@ public override void Navigation_to_shared_type_is_not_discovered_by_convention() var model = modelBuilder.FinalizeModel(); - var principal = model.FindEntityType(typeof(ReferenceNavigationToSharedType)); - var owned = principal.FindNavigation(nameof(ReferenceNavigationToSharedType.Navigation)).TargetEntityType; + var principal = model.FindEntityType(typeof(ReferenceNavigationToSharedType))!; + var owned = principal.FindNavigation(nameof(ReferenceNavigationToSharedType.Navigation))!.TargetEntityType; Assert.True(owned.IsOwned()); Assert.True(owned.HasSharedClrType); Assert.Equal( @@ -873,11 +887,11 @@ public override void Navigation_to_shared_type_is_not_discovered_by_convention() owned.DisplayName()); } - protected override TestModelBuilder CreateModelBuilder(Action configure = null) - => CreateTestModelBuilder(CosmosTestHelpers.Instance, configure); + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new GenericTestModelBuilder(Fixture, configure); } - public class CosmosGenericManyToMany : GenericManyToMany, IClassFixture + public class CosmosGenericManyToMany : ManyToManyTestBase, IClassFixture { public CosmosGenericManyToMany(CosmosModelBuilderFixture fixture) : base(fixture) @@ -920,14 +934,14 @@ public virtual void Can_use_shared_type_as_join_entity_with_partition_keys() var model = modelBuilder.FinalizeModel(); - var joinType = model.FindEntityType("JoinType"); + var joinType = model.FindEntityType("JoinType")!; Assert.NotNull(joinType); Assert.Equal(2, joinType.GetForeignKeys().Count()); - Assert.Equal(3, joinType.FindPrimaryKey().Properties.Count); + Assert.Equal(3, joinType.FindPrimaryKey()!.Properties.Count); Assert.Equal(6, joinType.GetProperties().Count()); Assert.Equal("DbContext", joinType.GetContainer()); Assert.Equal("PartitionId", joinType.GetPartitionKeyPropertyName()); - Assert.Equal("PartitionId", joinType.FindPrimaryKey().Properties.Last().Name); + Assert.Equal("PartitionId", joinType.FindPrimaryKey()!.Properties.Last().Name); } [ConditionalFact] @@ -962,11 +976,11 @@ public virtual void Can_use_implicit_join_entity_with_partition_keys() var joinType = model.FindEntityType("ManyToManyNavPrincipalNavDependent"); Assert.NotNull(joinType); Assert.Equal(2, joinType.GetForeignKeys().Count()); - Assert.Equal(3, joinType.FindPrimaryKey().Properties.Count); + Assert.Equal(3, joinType.FindPrimaryKey()!.Properties.Count); Assert.Equal(6, joinType.GetProperties().Count()); Assert.Equal("DbContext", joinType.GetContainer()); Assert.Equal("PartitionId", joinType.GetPartitionKeyPropertyName()); - Assert.Equal("PartitionId", joinType.FindPrimaryKey().Properties.Last().Name); + Assert.Equal("PartitionId", joinType.FindPrimaryKey()!.Properties.Last().Name); } [ConditionalFact] @@ -1010,11 +1024,11 @@ public virtual void Can_use_implicit_join_entity_with_partition_keys_changed() var joinType = model.FindEntityType("ManyToManyNavPrincipalNavDependent"); Assert.NotNull(joinType); Assert.Equal(2, joinType.GetForeignKeys().Count()); - Assert.Equal(3, joinType.FindPrimaryKey().Properties.Count); + Assert.Equal(3, joinType.FindPrimaryKey()!.Properties.Count); Assert.Equal(6, joinType.GetProperties().Count()); Assert.Equal("DbContext", joinType.GetContainer()); Assert.Equal("Partition2Id", joinType.GetPartitionKeyPropertyName()); - Assert.Equal("Partition2Id", joinType.FindPrimaryKey().Properties.Last().Name); + Assert.Equal("Partition2Id", joinType.FindPrimaryKey()!.Properties.Last().Name); } public override void Join_type_is_automatically_configured_by_convention() @@ -1023,7 +1037,7 @@ public override void Join_type_is_automatically_configured_by_convention() CoreStrings.NavigationNotAdded( nameof(ImplicitManyToManyA), nameof(ImplicitManyToManyA.Bs), "List"), Assert.Throws( - () => base.Join_type_is_automatically_configured_by_convention()).Message); + base.Join_type_is_automatically_configured_by_convention).Message); public override void ForeignKeyAttribute_configures_the_properties() // Cosmos many-to-many. Issue #23523. @@ -1031,13 +1045,13 @@ public override void ForeignKeyAttribute_configures_the_properties() CoreStrings.NavigationNotAdded( nameof(CategoryWithAttribute), nameof(CategoryWithAttribute.Products), "ICollection"), Assert.Throws( - () => base.ForeignKeyAttribute_configures_the_properties()).Message); + base.ForeignKeyAttribute_configures_the_properties).Message); - protected override TestModelBuilder CreateModelBuilder(Action configure = null) - => CreateTestModelBuilder(CosmosTestHelpers.Instance, configure); + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new GenericTestModelBuilder(Fixture, configure); } - public class CosmosGenericOwnedTypes : GenericOwnedTypes, IClassFixture + public class CosmosGenericOwnedTypes : OwnedTypesTestBase, IClassFixture { public CosmosGenericOwnedTypes(CosmosModelBuilderFixture fixture) : base(fixture) @@ -1072,12 +1086,12 @@ public virtual void Reference_type_is_discovered_as_owned() var model = modelBuilder.FinalizeModel(); - var owner = model.FindEntityType(typeof(OneToOneOwnerWithField)); + var owner = model.FindEntityType(typeof(OneToOneOwnerWithField))!; Assert.Equal(typeof(OneToOneOwnerWithField).FullName, owner.Name); - var ownership = owner.FindNavigation(nameof(OneToOneOwnerWithField.OwnedDependent)).ForeignKey; + var ownership = owner.FindNavigation(nameof(OneToOneOwnerWithField.OwnedDependent))!.ForeignKey; Assert.True(ownership.IsOwnership); - Assert.Equal(nameof(OneToOneOwnerWithField.OwnedDependent), ownership.PrincipalToDependent.Name); - Assert.Equal(nameof(OneToOneOwnedWithField.OneToOneOwner), ownership.DependentToPrincipal.Name); + Assert.Equal(nameof(OneToOneOwnerWithField.OwnedDependent), ownership.PrincipalToDependent!.Name); + Assert.Equal(nameof(OneToOneOwnedWithField.OneToOneOwner), ownership.DependentToPrincipal!.Name); Assert.Equal(nameof(OneToOneOwnerWithField.Id), ownership.PrincipalKey.Properties.Single().Name); var owned = ownership.DeclaringEntityType; Assert.Single(owned.GetForeignKeys()); @@ -1085,22 +1099,12 @@ public virtual void Reference_type_is_discovered_as_owned() Assert.Equal(1, model.GetEntityTypes().Count(e => e.ClrType == typeof(OneToOneOwnedWithField))); } - protected override TestModelBuilder CreateModelBuilder(Action configure = null) - => CreateTestModelBuilder(CosmosTestHelpers.Instance, configure); + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new GenericTestModelBuilder(Fixture, configure); } public class CosmosModelBuilderFixture : ModelBuilderFixtureBase { - public override void AssertEqual( - IEnumerable expectedProperties, - IEnumerable actualProperties, - bool assertOrder = false, - bool compareAnnotations = false) - { - expectedProperties = expectedProperties.Where(p => p.Name != "__jObject" && p.Name != "__id"); - actualProperties = actualProperties.Where(p => p.Name != "__jObject" && p.Name != "__id"); - - base.AssertEqual(expectedProperties, actualProperties, assertOrder, compareAnnotations); - } + public override TestHelpers TestHelpers => CosmosTestHelpers.Instance; } } diff --git a/test/EFCore.Cosmos.Tests/ModelBuilding/CosmosTestModelBuilderExtensions.cs b/test/EFCore.Cosmos.FunctionalTests/ModelBuilding/CosmosTestModelBuilderExtensions.cs similarity index 100% rename from test/EFCore.Cosmos.Tests/ModelBuilding/CosmosTestModelBuilderExtensions.cs rename to test/EFCore.Cosmos.FunctionalTests/ModelBuilding/CosmosTestModelBuilderExtensions.cs diff --git a/test/EFCore.Cosmos.FunctionalTests/TestUtilities/CosmosModelAsserter.cs b/test/EFCore.Cosmos.FunctionalTests/TestUtilities/CosmosModelAsserter.cs new file mode 100644 index 00000000000..1b73d9b1e16 --- /dev/null +++ b/test/EFCore.Cosmos.FunctionalTests/TestUtilities/CosmosModelAsserter.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// ReSharper disable once CheckNamespace + +namespace Microsoft.EntityFrameworkCore.TestUtilities; + +public class CosmosModelAsserter : ModelAsserter +{ + protected CosmosModelAsserter() + { + } + + public new static CosmosModelAsserter Instance { get; } = new(); + + public override void AssertEqual( + IEnumerable expectedProperties, + IEnumerable actualProperties, + bool assertOrder = false, + bool compareAnnotations = false) + { + expectedProperties = expectedProperties.Where(p => p.Name != "__jObject" && p.Name != "__id"); + actualProperties = actualProperties.Where(p => p.Name != "__jObject" && p.Name != "__id"); + + base.AssertEqual(expectedProperties, actualProperties, assertOrder, compareAnnotations); + } +} diff --git a/test/EFCore.Cosmos.FunctionalTests/TestUtilities/CosmosTestHelpers.cs b/test/EFCore.Cosmos.FunctionalTests/TestUtilities/CosmosTestHelpers.cs index 0425cd294e4..6f77e63a63e 100644 --- a/test/EFCore.Cosmos.FunctionalTests/TestUtilities/CosmosTestHelpers.cs +++ b/test/EFCore.Cosmos.FunctionalTests/TestUtilities/CosmosTestHelpers.cs @@ -13,6 +13,8 @@ protected CosmosTestHelpers() public static CosmosTestHelpers Instance { get; } = new(); + public override ModelAsserter ModelAsserter => CosmosModelAsserter.Instance; + public override IServiceCollection AddProviderServices(IServiceCollection services) => services.AddEntityFrameworkCosmos(); diff --git a/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.ModelSnapshot.cs b/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.ModelSnapshot.cs index 854d474921e..1d52aea804e 100644 --- a/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.ModelSnapshot.cs +++ b/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.ModelSnapshot.cs @@ -1488,7 +1488,7 @@ public virtual void Entity_splitting_is_stored_in_snapshot_with_tables() var fragment = orderEntityType.GetMappingFragments().Single(); var splitTable = relationalModel.FindTable(fragment.StoreObject.Name, fragment.StoreObject.Schema); Assert.Equal( - new[] { billingEntityType, orderEntityType }, + new[] { orderEntityType, billingEntityType }, splitTable.FindColumn("Shadow").PropertyMappings.Select(m => m.TableMapping.TypeBase)); Assert.Equal("bar", fragment["foo"]); @@ -8172,8 +8172,7 @@ protected IModel BuildModelFromSnapshotSource(string code) protected TestHelpers.TestModelBuilder CreateConventionalModelBuilder() => TestHelpers.CreateConventionBuilder( - customServices: new ServiceCollection() - .AddEntityFrameworkSqlServerNetTopologySuite()); + addServices: SqlServerNetTopologySuiteServiceCollectionExtensions.AddEntityFrameworkSqlServerNetTopologySuite); protected virtual MigrationsModelDiffer CreateModelDiffer(DbContextOptions options) => (MigrationsModelDiffer)TestHelpers.CreateContext(options).GetService(); diff --git a/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.cs b/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.cs index f6c3196a6f9..ab6da06f625 100644 --- a/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.cs +++ b/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.cs @@ -371,10 +371,28 @@ private static void MissingAnnotationCheck( nameof(CoreAnnotationNames) + "." + nameof(CoreAnnotationNames.AllNames) + " doesn't contain " + annotationName); } - foreach (var field in coreAnnotations.Concat( - typeof(RelationalAnnotationNames).GetFields().Where(f => f.Name != "Prefix"))) + var relationalAnnotations = typeof(RelationalAnnotationNames).GetFields() + .Where(f => f.FieldType == typeof(string) + && f.Name != "Prefix").ToList(); + + foreach (var field in relationalAnnotations) { var annotationName = (string)field.GetValue(null); + + if (field.Name != nameof(RelationalAnnotationNames.TpcMappingStrategy) + && field.Name != nameof(RelationalAnnotationNames.TptMappingStrategy) + && field.Name != nameof(RelationalAnnotationNames.TphMappingStrategy)) + { + Assert.True( + RelationalAnnotationNames.AllNames.Contains(annotationName), + nameof(RelationalAnnotationNames) + "." + nameof(RelationalAnnotationNames.AllNames) + " doesn't contain " + annotationName); + } + } + + foreach (var field in coreAnnotations.Concat(relationalAnnotations)) + { + var annotationName = (string)field.GetValue(null); + if (!invalidAnnotations.Contains(annotationName)) { var modelBuilder = FakeRelationalTestHelpers.Instance.CreateConventionBuilder(); diff --git a/test/EFCore.Design.Tests/Migrations/Design/SnapshotModelProcessorTest.cs b/test/EFCore.Design.Tests/Migrations/Design/SnapshotModelProcessorTest.cs index 097d3d461e0..c6b08ad63b3 100644 --- a/test/EFCore.Design.Tests/Migrations/Design/SnapshotModelProcessorTest.cs +++ b/test/EFCore.Design.Tests/Migrations/Design/SnapshotModelProcessorTest.cs @@ -272,11 +272,7 @@ private void AssertAnnotations(IMutableAnnotatable element) } private static IEnumerable GetAnnotationNames() - => typeof(RelationalAnnotationNames) - .GetTypeInfo() - .GetRuntimeFields() - .Where(p => p.Name != nameof(RelationalAnnotationNames.Prefix)) - .Select(p => (string)p.GetValue(null)); + => RelationalAnnotationNames.AllNames; private class DummyModelRuntimeInitializer : IModelRuntimeInitializer { diff --git a/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpDbContextGeneratorTest.cs b/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpDbContextGeneratorTest.cs index 73e294a56ce..61900460102 100644 --- a/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpDbContextGeneratorTest.cs +++ b/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpDbContextGeneratorTest.cs @@ -1359,10 +1359,10 @@ public Task ColumnOrder_is_ignored(bool useDataAnnotations) Assert.Null(entity.GetProperty("Property").GetColumnOrder()); }); - protected override void AddModelServices(IServiceCollection services) + protected override IServiceCollection AddModelServices(IServiceCollection services) => services.Replace(ServiceDescriptor.Singleton()); - protected override void AddScaffoldingServices(IServiceCollection services) + protected override IServiceCollection AddScaffoldingServices(IServiceCollection services) => services.Replace(ServiceDescriptor.Singleton()); private class TestModelAnnotationProvider : SqlServerAnnotationProvider diff --git a/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpEntityTypeGeneratorTest.cs b/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpEntityTypeGeneratorTest.cs index 7f9837184da..eb975bdad6d 100644 --- a/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpEntityTypeGeneratorTest.cs +++ b/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpEntityTypeGeneratorTest.cs @@ -2933,10 +2933,10 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) Assert.Equal("Post_Blogs_Source", skipNavigation.ForeignKey.GetConstraintName()); })); - protected override void AddModelServices(IServiceCollection services) + protected override IServiceCollection AddModelServices(IServiceCollection services) => services.Replace(ServiceDescriptor.Singleton()); - protected override void AddScaffoldingServices(IServiceCollection services) + protected override IServiceCollection AddScaffoldingServices(IServiceCollection services) => services.Replace(ServiceDescriptor.Singleton()); private class TestModelAnnotationProvider : SqlServerAnnotationProvider diff --git a/test/EFCore.Design.Tests/Scaffolding/Internal/ModelCodeGeneratorTestBase.cs b/test/EFCore.Design.Tests/Scaffolding/Internal/ModelCodeGeneratorTestBase.cs index ae1cc54c2d0..670ff9f2cc5 100644 --- a/test/EFCore.Design.Tests/Scaffolding/Internal/ModelCodeGeneratorTestBase.cs +++ b/test/EFCore.Design.Tests/Scaffolding/Internal/ModelCodeGeneratorTestBase.cs @@ -26,10 +26,7 @@ protected Task TestAsync( Action assertModel, bool skipBuild = false) { - var designServices = new ServiceCollection(); - AddModelServices(designServices); - - var modelBuilder = SqlServerTestHelpers.Instance.CreateConventionBuilder(customServices: designServices); + var modelBuilder = SqlServerTestHelpers.Instance.CreateConventionBuilder(addServices: AddModelServices); buildModel(modelBuilder); var model = modelBuilder.FinalizeModel(designTime: true, skipValidation: true); @@ -156,13 +153,11 @@ protected IServiceCollection CreateServices() return services; } - protected virtual void AddModelServices(IServiceCollection services) - { - } + protected virtual IServiceCollection AddModelServices(IServiceCollection services) + => services; - protected virtual void AddScaffoldingServices(IServiceCollection services) - { - } + protected virtual IServiceCollection AddScaffoldingServices(IServiceCollection services) + => services; protected static void AssertFileContents( string expectedCode, diff --git a/test/EFCore.InMemory.FunctionalTests/EFCore.InMemory.FunctionalTests.csproj b/test/EFCore.InMemory.FunctionalTests/EFCore.InMemory.FunctionalTests.csproj index a444262ee83..76178943737 100644 --- a/test/EFCore.InMemory.FunctionalTests/EFCore.InMemory.FunctionalTests.csproj +++ b/test/EFCore.InMemory.FunctionalTests/EFCore.InMemory.FunctionalTests.csproj @@ -18,6 +18,10 @@ + + + + diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderAssemblyScanTest.cs b/test/EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderAssemblyScanTest.cs similarity index 97% rename from test/EFCore.Tests/ModelBuilding/ModelBuilderAssemblyScanTest.cs rename to test/EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderAssemblyScanTest.cs index 012579d3b76..816272ff9d6 100644 --- a/test/EFCore.Tests/ModelBuilding/ModelBuilderAssemblyScanTest.cs +++ b/test/EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderAssemblyScanTest.cs @@ -3,11 +3,11 @@ namespace Microsoft.EntityFrameworkCore.ModelBuilding; -public class ModelBuilderAssemblyScanTest : ModelBuilderTest +public class InMemoryModelBuilderAssemblyScanTest : ModelBuilderTest { private readonly Assembly _mockEntityTypeAssembly; - public ModelBuilderAssemblyScanTest() + public InMemoryModelBuilderAssemblyScanTest() { _mockEntityTypeAssembly = MockAssembly.Create( typeof(ScannerCustomerEntityConfiguration), typeof(ScannerCustomerEntityConfiguration2), diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericRelationshipStringTest.cs b/test/EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderGenericRelationshipStringTest.cs similarity index 88% rename from test/EFCore.Tests/ModelBuilding/ModelBuilderGenericRelationshipStringTest.cs rename to test/EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderGenericRelationshipStringTest.cs index c2e0d7a6092..5da68eb1a94 100644 --- a/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericRelationshipStringTest.cs +++ b/test/EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderGenericRelationshipStringTest.cs @@ -5,74 +5,64 @@ namespace Microsoft.EntityFrameworkCore.ModelBuilding; -public class ModelBuilderGenericRelationshipStringTest : ModelBuilderGenericTest +public class InMemoryModelBuilderGenericRelationshipStringTest : InMemoryModelBuilderGenericTest { - public class GenericOneToManyString : OneToManyTestBase + public class GenericOneToManyString : InMemoryOneToMany { - public GenericOneToManyString(ModelBuilderFixtureBase fixture) + public GenericOneToManyString(InMemoryModelBuilderFixture fixture) : base(fixture) { } - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new GenericStringTestModelBuilder(testHelpers, configure); + protected override TestModelBuilder CreateModelBuilder(Action? configure) + => new GenericStringTestModelBuilder(Fixture, configure); } - public class GenericManyToOneString : ManyToOneTestBase + public class GenericManyToOneString : InMemoryManyToOne { - public GenericManyToOneString(ModelBuilderFixtureBase fixture) + public GenericManyToOneString(InMemoryModelBuilderFixture fixture) : base(fixture) { } - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new GenericStringTestModelBuilder(testHelpers, configure); + protected override TestModelBuilder CreateModelBuilder(Action? configure) + => new GenericStringTestModelBuilder(Fixture, configure); } - public class GenericManyToManyString : ManyToManyTestBase + public class GenericManyToManyString : InMemoryManyToMany { - public GenericManyToManyString(ModelBuilderFixtureBase fixture) + public GenericManyToManyString(InMemoryModelBuilderFixture fixture) : base(fixture) { } - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new GenericStringTestModelBuilder(testHelpers, configure); + protected override TestModelBuilder CreateModelBuilder(Action? configure) + => new GenericStringTestModelBuilder(Fixture, configure); } - public class GenericOneToOneString : OneToOneTestBase + public class GenericOneToOneString : InMemoryOneToOne { - public GenericOneToOneString(ModelBuilderFixtureBase fixture) + public GenericOneToOneString(InMemoryModelBuilderFixture fixture) : base(fixture) { } - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new GenericStringTestModelBuilder(testHelpers, configure); + protected override TestModelBuilder CreateModelBuilder(Action? configure) + => new GenericStringTestModelBuilder(Fixture, configure); } - public class GenericOwnedTypesString : OwnedTypesTestBase + public class GenericOwnedTypesString : InMemoryOwnedTypes { - public GenericOwnedTypesString(ModelBuilderFixtureBase fixture) + public GenericOwnedTypesString(InMemoryModelBuilderFixture fixture) : base(fixture) { } - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new GenericStringTestModelBuilder(testHelpers, configure); + protected override TestModelBuilder CreateModelBuilder(Action? configure) + => new GenericStringTestModelBuilder(Fixture, configure); } public class GenericStringTestModelBuilder : TestModelBuilder { - public GenericStringTestModelBuilder(TestHelpers testHelpers, Action? configure) - : base(testHelpers, configure) + public GenericStringTestModelBuilder(ModelBuilderFixtureBase fixture, Action? configure) + : base(fixture, configure) { } diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericRelationshipTypeTest.cs b/test/EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderGenericRelationshipTypeTest.cs similarity index 94% rename from test/EFCore.Tests/ModelBuilding/ModelBuilderGenericRelationshipTypeTest.cs rename to test/EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderGenericRelationshipTypeTest.cs index 9da8322f71d..8fb2e1afb6a 100644 --- a/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericRelationshipTypeTest.cs +++ b/test/EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderGenericRelationshipTypeTest.cs @@ -5,38 +5,34 @@ namespace Microsoft.EntityFrameworkCore.ModelBuilding; -public class ModelBuilderGenericRelationshipTypeTest : ModelBuilderGenericTest +public class InMemoryModelBuilderGenericRelationshipTypeTest : InMemoryModelBuilderGenericTest { - public class GenericOneToOneType : OneToOneTestBase + public class GenericOneToOneType : InMemoryOneToOne { - public GenericOneToOneType(ModelBuilderFixtureBase fixture) + public GenericOneToOneType(InMemoryModelBuilderFixture fixture) : base(fixture) { } - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new GenericTypeTestModelBuilder(testHelpers, configure); + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new GenericTypeTestModelBuilder(Fixture, configure); } - public class GenericNonRelationshipTest : NonRelationshipTestBase + public class GenericNonRelationshipTest : InMemoryNonRelationship { - public GenericNonRelationshipTest(ModelBuilderFixtureBase fixture) + public GenericNonRelationshipTest(InMemoryModelBuilderFixture fixture) : base(fixture) { } - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new GenericTypeTestModelBuilder(testHelpers, configure); + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new GenericTypeTestModelBuilder(Fixture, configure); } public class GenericTypeTestModelBuilder : TestModelBuilder { - public GenericTypeTestModelBuilder(TestHelpers testHelpers, Action? configure) - : base(testHelpers, configure) + public GenericTypeTestModelBuilder(ModelBuilderFixtureBase fixture, Action? configure) + : base(fixture, configure) { } diff --git a/test/EFCore.InMemory.Tests/ModelBuilding/InMemoryModelBuilderGenericTest.cs b/test/EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderGenericTest.cs similarity index 68% rename from test/EFCore.InMemory.Tests/ModelBuilding/InMemoryModelBuilderGenericTest.cs rename to test/EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderGenericTest.cs index 44a02ef57c5..b9fb5ebc99b 100644 --- a/test/EFCore.InMemory.Tests/ModelBuilding/InMemoryModelBuilderGenericTest.cs +++ b/test/EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderGenericTest.cs @@ -1,48 +1,90 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel.DataAnnotations; +using Microsoft.EntityFrameworkCore.Metadata.Internal; + +#nullable enable // ReSharper disable InconsistentNaming namespace Microsoft.EntityFrameworkCore.ModelBuilding; -public class InMemoryModelBuilderGenericTest : ModelBuilderGenericTest +public class InMemoryModelBuilderGenericTest : InMemoryModelBuilderTest { - public class InMemoryGenericNonRelationship : GenericNonRelationship, IClassFixture + public class InMemoryGenericNonRelationship : InMemoryNonRelationship { public InMemoryGenericNonRelationship(InMemoryModelBuilderFixture fixture) : base(fixture) { } - protected override TestModelBuilder CreateModelBuilder(Action configure = null) - => CreateTestModelBuilder(InMemoryTestHelpers.Instance, configure); + [ConditionalFact] + public void Can_discover_large_models_through_navigations() + { + var modelBuilder = CreateModelBuilder(); + + modelBuilder.Entity(); + + Assert.Equal(2000, modelBuilder.Model.GetEntityTypes().Count()); + } + + [ConditionalFact] + public virtual void Changing_propertyInfo_updates_Property() + { + var modelBuilder = CreateModelBuilder(); + + modelBuilder.Entity().Property(e => ((IReplaceable)e).Property); + + modelBuilder.FinalizeModel(); + + var property = modelBuilder.Model.FindEntityType(typeof(DoubleProperty))!.GetProperty("Property"); + Assert.EndsWith(typeof(IReplaceable).Name + "." + nameof(IReplaceable.Property), property.GetIdentifyingMemberInfo()!.Name); + } + + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new GenericTestModelBuilder(Fixture, configure); } - public class InMemoryGenericComplexTypeTestBase : GenericComplexType, IClassFixture + public class InMemoryGenericComplexType : InMemoryComplexType { - public InMemoryGenericComplexTypeTestBase(InMemoryModelBuilderFixture fixture) + public InMemoryGenericComplexType(InMemoryModelBuilderFixture fixture) : base(fixture) { } - protected override TestModelBuilder CreateModelBuilder(Action configure = null) - => CreateTestModelBuilder(InMemoryTestHelpers.Instance, configure); + [ConditionalFact] + public virtual void Changing_propertyInfo_updates_Property() + { + var modelBuilder = CreateModelBuilder(); + + modelBuilder + .Ignore() + .Entity().ComplexProperty(e => e.DoubleProperty).Property(e => ((IReplaceable?)e)!.Property); + + modelBuilder.FinalizeModel(); + + var property = modelBuilder.Model.FindEntityType(typeof(ComplexProperties))!.FindComplexProperty(nameof(DoubleProperty))! + .ComplexType.FindProperty("Property")!; + Assert.EndsWith(typeof(IReplaceable).Name + "." + nameof(IReplaceable.Property), property.GetIdentifyingMemberInfo()!.Name); + } + + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new GenericTestModelBuilder(Fixture, configure); } - public class InMemoryGenericInheritance : GenericInheritance, IClassFixture + public class InMemoryGenericInheritance : InMemoryInheritance { public InMemoryGenericInheritance(InMemoryModelBuilderFixture fixture) : base(fixture) { } - protected override TestModelBuilder CreateModelBuilder(Action configure = null) - => CreateTestModelBuilder(InMemoryTestHelpers.Instance, configure); + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new GenericTestModelBuilder(Fixture, configure); } - public class InMemoryGenericOneToMany : GenericOneToMany, IClassFixture + public class InMemoryGenericOneToMany : InMemoryOneToMany { public InMemoryGenericOneToMany(InMemoryModelBuilderFixture fixture) : base(fixture) @@ -128,12 +170,11 @@ private class ModifierGroupHeader [DatabaseGenerated(DatabaseGeneratedOption.None)] public int AccountId { get; set; } - [Required] [StringLength(50)] - public string GroupBatchName { get; set; } + public string GroupBatchName { get; set; } = null!; [StringLength(200)] - public string GroupBatchNameAlt { get; set; } + public string? GroupBatchNameAlt { get; set; } public int MaxModifierSelectCount { get; set; } @@ -143,40 +184,49 @@ private class ModifierGroupHeader public DateTime CreatedDate { get; set; } - [Required] [StringLength(50)] - public string CreatedBy { get; set; } + public string CreatedBy { get; set; } = null!; public DateTime ModifiedDate { get; set; } - [Required] [StringLength(50)] - public string ModifiedBy { get; set; } + public string ModifiedBy { get; set; } = null!; public bool? IsFollowSet { get; set; } public virtual ICollection ModifierGroupHeader1 { get; set; } = new HashSet(); - public virtual ModifierGroupHeader ModifierGroupHeader2 { get; set; } + public virtual ModifierGroupHeader? ModifierGroupHeader2 { get; set; } + } + + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new GenericTestModelBuilder(Fixture, configure); + } + + public class InMemoryGenericManyToMany : InMemoryManyToMany + { + public InMemoryGenericManyToMany(InMemoryModelBuilderFixture fixture) + : base(fixture) + { } - protected override TestModelBuilder CreateModelBuilder(Action configure = null) - => CreateTestModelBuilder(InMemoryTestHelpers.Instance, configure); + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new GenericTestModelBuilder(Fixture, configure); } - public class InMemoryGenericManyToOne : GenericManyToOne, IClassFixture + public class InMemoryGenericManyToOne : InMemoryManyToOne { public InMemoryGenericManyToOne(InMemoryModelBuilderFixture fixture) : base(fixture) { } - protected override TestModelBuilder CreateModelBuilder(Action configure = null) - => CreateTestModelBuilder(InMemoryTestHelpers.Instance, configure); + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new GenericTestModelBuilder(Fixture, configure); } - public class InMemoryGenericOneToOne : GenericOneToOne, IClassFixture + public class InMemoryGenericOneToOne : InMemoryOneToOne { public InMemoryGenericOneToOne(InMemoryModelBuilderFixture fixture) : base(fixture) @@ -258,26 +308,22 @@ private class Node public int PreviousNodeId { get; set; } public int NextNodeId { get; set; } - public Node PreviousNode { get; set; } - public Node NextNode { get; set; } + public Node? PreviousNode { get; set; } + public Node? NextNode { get; set; } } - protected override TestModelBuilder CreateModelBuilder(Action configure = null) - => CreateTestModelBuilder(InMemoryTestHelpers.Instance, configure); + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new GenericTestModelBuilder(Fixture, configure); } - public class InMemoryGenericOwnedTypes : GenericOwnedTypes, IClassFixture + public class InMemoryGenericOwnedTypes : InMemoryOwnedTypes { public InMemoryGenericOwnedTypes(InMemoryModelBuilderFixture fixture) : base(fixture) { } - protected override TestModelBuilder CreateModelBuilder(Action configure = null) - => CreateTestModelBuilder(InMemoryTestHelpers.Instance, configure); - } - - public class InMemoryModelBuilderFixture : ModelBuilderFixtureBase - { + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new GenericTestModelBuilder(Fixture, configure); } } diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericStringTest.cs b/test/EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderNonGenericStringTest.cs similarity index 89% rename from test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericStringTest.cs rename to test/EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderNonGenericStringTest.cs index 711b77f3794..7cb3ebed587 100644 --- a/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericStringTest.cs +++ b/test/EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderNonGenericStringTest.cs @@ -9,19 +9,17 @@ // ReSharper disable InconsistentNaming namespace Microsoft.EntityFrameworkCore.ModelBuilding; -public class ModelBuilderNonGenericStringTest : ModelBuilderNonGenericTest +public class InMemoryModelBuilderNonGenericStringTest : InMemoryModelBuilderNonGenericTest { - public class NonGenericStringOwnedTypes : OwnedTypesTestBase + public class NonGenericStringOwnedTypes : InMemoryOwnedTypes { - public NonGenericStringOwnedTypes(ModelBuilderFixtureBase fixture) + public NonGenericStringOwnedTypes(InMemoryModelBuilderFixture fixture) : base(fixture) { } - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new NonGenericStringTestModelBuilder(testHelpers, configure); + protected override TestModelBuilder CreateModelBuilder(Action? configure) + => new NonGenericStringTestModelBuilder(Fixture, configure); public override void OwnedType_can_derive_from_Collection() // Shadow navigations. Issue #3864. @@ -32,17 +30,15 @@ public override void OwnedType_can_derive_from_Collection() base.OwnedType_can_derive_from_Collection).Message); } - public class NonGenericStringOneToManyType : OneToManyTestBase + public class NonGenericStringOneToManyType : InMemoryOneToMany { - public NonGenericStringOneToManyType(ModelBuilderFixtureBase fixture) + public NonGenericStringOneToManyType(InMemoryModelBuilderFixture fixture) : base(fixture) { } - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new NonGenericStringTestModelBuilder(testHelpers, configure); + protected override TestModelBuilder CreateModelBuilder(Action? configure) + => new NonGenericStringTestModelBuilder(Fixture, configure); public override void WithMany_pointing_to_keyless_entity_throws() // Test throws exception before reaching the first exception due to entity type being property bag entity @@ -50,36 +46,32 @@ public override void WithMany_pointing_to_keyless_entity_throws() base.WithMany_pointing_to_keyless_entity_throws); } - public class NonGenericStringManyToOneType : ManyToOneTestBase + public class NonGenericStringManyToOneType : InMemoryManyToOne { - public NonGenericStringManyToOneType(ModelBuilderFixtureBase fixture) + public NonGenericStringManyToOneType(InMemoryModelBuilderFixture fixture) : base(fixture) { } - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new NonGenericStringTestModelBuilder(testHelpers, configure); + protected override TestModelBuilder CreateModelBuilder(Action? configure) + => new NonGenericStringTestModelBuilder(Fixture, configure); } - public class NonGenericStringOneToOneType : OneToOneTestBase + public class NonGenericStringOneToOneType : InMemoryOneToOne { - public NonGenericStringOneToOneType(ModelBuilderFixtureBase fixture) + public NonGenericStringOneToOneType(InMemoryModelBuilderFixture fixture) : base(fixture) { } - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new NonGenericStringTestModelBuilder(testHelpers, configure); + protected override TestModelBuilder CreateModelBuilder(Action? configure) + => new NonGenericStringTestModelBuilder(Fixture, configure); } private class NonGenericStringTestModelBuilder : TestModelBuilder { - public NonGenericStringTestModelBuilder(TestHelpers testHelpers, Action? configure) - : base(testHelpers, configure) + public NonGenericStringTestModelBuilder(ModelBuilderFixtureBase fixture, Action? configure) + : base(fixture, configure) { } diff --git a/test/EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderNonGenericTest.cs b/test/EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderNonGenericTest.cs new file mode 100644 index 00000000000..f15c089a854 --- /dev/null +++ b/test/EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderNonGenericTest.cs @@ -0,0 +1,188 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#nullable enable + +// ReSharper disable InconsistentNaming +namespace Microsoft.EntityFrameworkCore.ModelBuilding; + +public class InMemoryModelBuilderNonGenericTest : InMemoryModelBuilderTest +{ + public class InMemoryNonGenericNonRelationship : InMemoryNonRelationship + { + public InMemoryNonGenericNonRelationship(InMemoryModelBuilderFixture fixture) + : base(fixture) + { + } + + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new NonGenericTestModelBuilder(Fixture, configure); + } + + public class InMemoryNonGenericComplexType : InMemoryComplexType + { + public InMemoryNonGenericComplexType(InMemoryModelBuilderFixture fixture) + : base(fixture) + { + } + + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new NonGenericTestModelBuilder(Fixture, configure); + } + + public class InMemoryNonGenericInheritance : InMemoryInheritance + { + public InMemoryNonGenericInheritance(InMemoryModelBuilderFixture fixture) + : base(fixture) + { + } + + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new NonGenericTestModelBuilder(Fixture, configure); + } + + public class InMemoryNonGenericOneToMany : InMemoryOneToMany + { + public InMemoryNonGenericOneToMany(InMemoryModelBuilderFixture fixture) + : base(fixture) + { + } + [ConditionalFact] + public virtual void HasOne_with_just_string_navigation_for_non_CLR_property_throws() + { + var modelBuilder = CreateModelBuilder(); + + Assert.Equal( + CoreStrings.NoClrNavigation("Snoop", nameof(Dr)), + Assert.Throws( + () => + ((NonGenericTestEntityTypeBuilder)modelBuilder.Entity()).GetInfrastructure() + .HasOne("Snoop")).Message); + } + + [ConditionalFact] + public virtual void HasMany_with_just_string_navigation_for_non_CLR_property_throws() + { + var modelBuilder = CreateModelBuilder(); + + Assert.Equal( + CoreStrings.NoClrNavigation("Snoop", nameof(Dr)), + Assert.Throws( + () => + ((NonGenericTestEntityTypeBuilder)modelBuilder.Entity()).GetInfrastructure() + .HasMany("Snoop")).Message); + } + + [ConditionalFact] + public virtual void HasMany_with_a_non_collection_just_string_navigation_CLR_property_throws() + { + var modelBuilder = CreateModelBuilder(); + + Assert.Equal( + CoreStrings.NavigationCollectionWrongClrType("Dre", nameof(Dr), nameof(Dre), "T"), + Assert.Throws( + () => + ((NonGenericTestEntityTypeBuilder)modelBuilder.Entity()).GetInfrastructure() + .HasMany("Dre")).Message); + } + + [ConditionalFact] //Issue#13108 + public virtual void HasForeignKey_infers_type_for_shadow_property_when_not_specified() + { + var modelBuilder = CreateModelBuilder(); + + modelBuilder.Entity( + e => + { + e.HasKey(c => c.Key); + ((NonGenericTestEntityTypeBuilder)e).GetInfrastructure().Property("ParentKey"); + e.HasOne(c => c.Parent).WithMany(c => c.Children).HasForeignKey("ParentKey"); + }); + + modelBuilder.Entity().HasKey(c => c.Key); + + var model = (IConventionModel)modelBuilder.FinalizeModel(); + + var property = model + .FindEntityType(typeof(ComplexCaseChild13108))!.GetProperties().Single(p => p.Name == "ParentKey"); + Assert.Equal(typeof(int), property.ClrType); + Assert.Equal(ConfigurationSource.Explicit, property.GetTypeConfigurationSource()); + } + + protected class ComplexCaseChild13108 + { + public int Key { get; set; } + public string? Id { get; set; } + private int ParentKey { get; set; } + public ComplexCaseParent13108? Parent { get; set; } + } + + protected class ComplexCaseParent13108 + { + public int Key { get; set; } + public string? Id { get; set; } + public ICollection? Children { get; set; } + } + + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new NonGenericTestModelBuilder(Fixture, configure); + } + + public class InMemoryNonGenericManyToMany : InMemoryManyToMany + { + public InMemoryNonGenericManyToMany(InMemoryModelBuilderFixture fixture) + : base(fixture) + { + } + + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new NonGenericTestModelBuilder(Fixture, configure); + } + + public class InMemoryNonGenericManyToOne : InMemoryManyToOne + { + public InMemoryNonGenericManyToOne(InMemoryModelBuilderFixture fixture) + : base(fixture) + { + } + + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new NonGenericTestModelBuilder(Fixture, configure); + } + + public class InMemoryNonGenericOneToOne : InMemoryOneToOne + { + public InMemoryNonGenericOneToOne(InMemoryModelBuilderFixture fixture) + : base(fixture) + { + } + + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new NonGenericTestModelBuilder(Fixture, configure); + } + + public class InMemoryNonGenericOwnedTypes : InMemoryOwnedTypes + { + public InMemoryNonGenericOwnedTypes(InMemoryModelBuilderFixture fixture) + : base(fixture) + { + } + + [ConditionalFact] + public virtual void OwnsOne_HasOne_with_just_string_navigation_for_non_CLR_property_throws() + { + var modelBuilder = CreateModelBuilder(); + + Assert.Equal( + CoreStrings.NoClrNavigation("Snoop", nameof(Dre)), + Assert.Throws( + () => + ((NonGenericTestOwnedNavigationBuilder)modelBuilder.Entity().OwnsOne(e => e.Dre)) + .GetInfrastructure() + .HasOne("Snoop")).Message); + } + + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new NonGenericTestModelBuilder(Fixture, configure); + } +} diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericUnqualifiedStringTest.cs b/test/EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderNonGenericUnqualifiedStringTest.cs similarity index 94% rename from test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericUnqualifiedStringTest.cs rename to test/EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderNonGenericUnqualifiedStringTest.cs index 9d4b2af94d0..56a02ef2629 100644 --- a/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericUnqualifiedStringTest.cs +++ b/test/EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderNonGenericUnqualifiedStringTest.cs @@ -5,25 +5,23 @@ namespace Microsoft.EntityFrameworkCore.ModelBuilding; -public class ModelBuilderNonGenericUnqualifiedStringTest : ModelBuilderNonGenericTest +public class InMemoryModelBuilderNonGenericUnqualifiedStringTest : InMemoryModelBuilderNonGenericTest { - public class NonGenericStringOneToOneType : OneToOneTestBase + public class NonGenericStringOneToOne : InMemoryOneToOne { - public NonGenericStringOneToOneType(ModelBuilderFixtureBase fixture) + public NonGenericStringOneToOne(InMemoryModelBuilderFixture fixture) : base(fixture) { } - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new NonGenericStringTestModelBuilder(testHelpers, configure); + protected override TestModelBuilder CreateModelBuilder(Action? configure) + => new NonGenericStringTestModelBuilder(Fixture, configure); } private class NonGenericStringTestModelBuilder : TestModelBuilder { - public NonGenericStringTestModelBuilder(TestHelpers testHelpers, Action? configure) - : base(testHelpers, configure) + public NonGenericStringTestModelBuilder(ModelBuilderFixtureBase fixture, Action? configure) + : base(fixture, configure) { } diff --git a/test/EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderTest.cs b/test/EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderTest.cs new file mode 100644 index 00000000000..5cc42b93181 --- /dev/null +++ b/test/EFCore.InMemory.FunctionalTests/ModelBuilding/InMemoryModelBuilderTest.cs @@ -0,0 +1,79 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#nullable enable + +// ReSharper disable InconsistentNaming +namespace Microsoft.EntityFrameworkCore.ModelBuilding; + +public class InMemoryModelBuilderTest : ModelBuilderTest +{ + public abstract class InMemoryNonRelationship : NonRelationshipTestBase, IClassFixture + { + public InMemoryNonRelationship(InMemoryModelBuilderFixture fixture) + : base(fixture) + { + } + } + + public abstract class InMemoryComplexType : ComplexTypeTestBase, IClassFixture + { + public InMemoryComplexType(InMemoryModelBuilderFixture fixture) + : base(fixture) + { + } + } + + public abstract class InMemoryInheritance : InheritanceTestBase, IClassFixture + { + public InMemoryInheritance(InMemoryModelBuilderFixture fixture) + : base(fixture) + { + } + } + + public abstract class InMemoryOneToMany : OneToManyTestBase, IClassFixture + { + public InMemoryOneToMany(InMemoryModelBuilderFixture fixture) + : base(fixture) + { + } + } + + public abstract class InMemoryManyToMany : ManyToManyTestBase, IClassFixture + { + public InMemoryManyToMany(InMemoryModelBuilderFixture fixture) + : base(fixture) + { + } + } + + public abstract class InMemoryManyToOne : ManyToOneTestBase, IClassFixture + { + public InMemoryManyToOne(InMemoryModelBuilderFixture fixture) + : base(fixture) + { + } + } + + public abstract class InMemoryOneToOne : OneToOneTestBase, IClassFixture + { + public InMemoryOneToOne(InMemoryModelBuilderFixture fixture) + : base(fixture) + { + } + } + + public abstract class InMemoryOwnedTypes : OwnedTypesTestBase, IClassFixture + { + public InMemoryOwnedTypes(InMemoryModelBuilderFixture fixture) + : base(fixture) + { + } + } + + public class InMemoryModelBuilderFixture : ModelBuilderFixtureBase + { + public override TestHelpers TestHelpers => InMemoryTestHelpers.Instance; + } +} diff --git a/test/EFCore.Tests/ModelBuilding/PropertyBagEntityTypeTest.cs b/test/EFCore.InMemory.FunctionalTests/ModelBuilding/PropertyBagEntityTypeTest.cs similarity index 100% rename from test/EFCore.Tests/ModelBuilding/PropertyBagEntityTypeTest.cs rename to test/EFCore.InMemory.FunctionalTests/ModelBuilding/PropertyBagEntityTypeTest.cs diff --git a/test/EFCore.Relational.Tests/ModelBuilding/RelationalModelBuilderTest.cs b/test/EFCore.Relational.Specification.Tests/ModelBuilding/RelationalModelBuilderTest.cs similarity index 96% rename from test/EFCore.Relational.Tests/ModelBuilding/RelationalModelBuilderTest.cs rename to test/EFCore.Relational.Specification.Tests/ModelBuilding/RelationalModelBuilderTest.cs index 919dfb2992a..ade65a48d14 100644 --- a/test/EFCore.Relational.Tests/ModelBuilding/RelationalModelBuilderTest.cs +++ b/test/EFCore.Relational.Specification.Tests/ModelBuilding/RelationalModelBuilderTest.cs @@ -1047,9 +1047,92 @@ protected class JsonEntityWithNesting public List OwnedCollection2 { get; set; } } #nullable enable + + public override void Can_configure_owned_type() + { + var modelBuilder = CreateModelBuilder(); + + modelBuilder.Ignore(); + modelBuilder.Ignore(); + + var ownedBuilder = modelBuilder.Entity().OwnsOne(c => c.Details) + .ToTable( + "OtherCustomerDetails", tb => + tb.HasCheckConstraint("CK_CustomerDetails_T", "AlternateKey <> 0").HasName("CK_Guid")); + ownedBuilder.Property(d => d.CustomerId); + ownedBuilder.HasIndex(d => d.CustomerId); + ownedBuilder.WithOwner(d => (OtherCustomer?)d.Customer) + .HasPrincipalKey(c => c.AlternateKey); + + modelBuilder.Entity().OwnsOne( + c => c.Details, b => + { + b.ToTable( + "SpecialCustomerDetails", tb => + tb.HasCheckConstraint("CK_CustomerDetails_T", "AlternateKey <> 0").HasName("CK_Guid")); + b.Property(d => d.CustomerId); + b.HasIndex(d => d.CustomerId); + b.WithOwner(d => (SpecialCustomer?)d.Customer) + .HasPrincipalKey(c => c.AlternateKey); + }); + + var model = modelBuilder.FinalizeModel(); + + var owner1 = model.FindEntityType(typeof(OtherCustomer))!; + Assert.Equal(typeof(OtherCustomer).FullName, owner1.Name); + AssertOwnership(owner1); + + var owner2 = model.FindEntityType(typeof(SpecialCustomer))!; + Assert.Equal(typeof(SpecialCustomer).FullName, owner2.Name); + AssertOwnership(owner2); + + Assert.Null(model.FindEntityType(typeof(CustomerDetails))); + Assert.Equal(2, model.GetEntityTypes().Count(e => e.ClrType == typeof(CustomerDetails))); + + static void AssertOwnership(IEntityType owner) + { + var ownership1 = owner.FindNavigation(nameof(Customer.Details))!.ForeignKey; + Assert.True(ownership1.IsOwnership); + Assert.Equal(nameof(Customer.Details), ownership1.PrincipalToDependent?.Name); + Assert.Equal("CustomerAlternateKey", ownership1.Properties.Single().Name); + Assert.Equal(nameof(Customer.AlternateKey), ownership1.PrincipalKey.Properties.Single().Name); + var owned = ownership1.DeclaringEntityType; + Assert.Equal(owner.ShortName() + "Details", owned.GetTableName()); + var checkConstraint = owned.GetCheckConstraints().Single(); + Assert.Same(owned, checkConstraint.EntityType); + Assert.Equal("CK_CustomerDetails_T", checkConstraint.ModelName); + Assert.Equal("AlternateKey <> 0", checkConstraint.Sql); + Assert.Equal("CK_Guid", checkConstraint.Name); + Assert.Single(owned.GetForeignKeys()); + var index = owned.GetIndexes().Single(); + Assert.Same(owned, index.DeclaringEntityType); + Assert.Equal(nameof(CustomerDetails.CustomerId), index.Properties.Single().Name); + Assert.Equal( + new[] { "CustomerAlternateKey", nameof(CustomerDetails.CustomerId), nameof(CustomerDetails.Id) }, + owned.GetProperties().Select(p => p.Name)); + } + } + public override void Can_configure_owned_type_key() + { + var modelBuilder = CreateModelBuilder(); + var model = modelBuilder.Model; + + modelBuilder.Entity().OwnsOne(c => c.Details) + .ToTable("Details") + .HasKey(c => c.Id); + + modelBuilder.FinalizeModel(); + + var owner = model.FindEntityType(typeof(Customer))!; + var owned = owner.FindNavigation(nameof(Customer.Details))!.ForeignKey.DeclaringEntityType; + Assert.Equal( + new[] { nameof(CustomerDetails.Id), nameof(CustomerDetails.CustomerId) }, + owned.GetProperties().Select(p => p.Name).ToArray()); + Assert.Equal(nameof(CustomerDetails.Id), owned.FindPrimaryKey()!.Properties.Single().Name); + } } - public class RelationalModelBuilderFixture : ModelBuilderFixtureBase + public abstract class RelationalModelBuilderFixture : ModelBuilderFixtureBase { } diff --git a/test/EFCore.Relational.Tests/ModelBuilding/RelationalTestModelBuilderExtensions.cs b/test/EFCore.Relational.Specification.Tests/ModelBuilding/RelationalTestModelBuilderExtensions.cs similarity index 100% rename from test/EFCore.Relational.Tests/ModelBuilding/RelationalTestModelBuilderExtensions.cs rename to test/EFCore.Relational.Specification.Tests/ModelBuilding/RelationalTestModelBuilderExtensions.cs diff --git a/test/EFCore.Relational.Specification.Tests/Query/JsonQueryAdHocTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/JsonQueryAdHocTestBase.cs index c5c3dadfed6..d413e0d7d46 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/JsonQueryAdHocTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/JsonQueryAdHocTestBase.cs @@ -873,7 +873,7 @@ public virtual async Task Project_proxies_entity_with_json(bool async) protected void OnConfiguringLazyLoadingProxies(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseLazyLoadingProxies(); - protected void AddServicesLazyLoadingProxies(IServiceCollection addServices) + protected IServiceCollection AddServicesLazyLoadingProxies(IServiceCollection addServices) => addServices.AddEntityFrameworkProxies(); private void SeedLazyLoadingProxies(MyContextLazyLoadingProxies ctx) diff --git a/test/EFCore.Relational.Specification.Tests/Scaffolding/CompiledModelRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Scaffolding/CompiledModelRelationalTestBase.cs index 6ebf45ed34c..33e45752ac6 100644 --- a/test/EFCore.Relational.Specification.Tests/Scaffolding/CompiledModelRelationalTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Scaffolding/CompiledModelRelationalTestBase.cs @@ -588,7 +588,6 @@ protected virtual void AssertTpc(IModel model) "bar2", id.FindOverrides(StoreObjectIdentifier.Create(principalBase, StoreObjectType.View)!.Value)!["foo"]); - var enum1 = principalBase.FindProperty(nameof(PrincipalBase.Enum1))!; Assert.Equal(AnEnum.A, enum1.GetDefaultValue()); @@ -599,8 +598,7 @@ protected virtual void AssertTpc(IModel model) Assert.True(alternateIndex.IsUnique); Assert.Equal("PrincipalIndex", alternateIndex.Name); Assert.Equal("PIX", alternateIndex.GetDatabaseName()); - Assert.Null(alternateIndex[RelationalAnnotationNames.Filter]); - Assert.Null(alternateIndex.GetFilter()); + Assert.Equal("AlternateId <> NULL", alternateIndex.GetFilter()); Assert.Equal(new[] { alternateIndex }, principalBaseId.GetContainingIndexes()); @@ -1213,43 +1211,4 @@ protected override BuildSource AddReferences(BuildSource build, [CallerFilePath] protected override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder) => base.AddOptions(builder) .ConfigureWarnings(w => w.Ignore(RelationalEventId.ForeignKeyTpcPrincipalWarning)); - - protected override (TContext?, IModel?) Test( - Action? onModelCreating = null, - Action? assertModel = null, - Action? useContext = null, - Action? onConfiguring = null, - CompiledModelCodeGenerationOptions? options = null, - Action? addServices = null, - Action? addDesignTimeServices = null, - string? expectedExceptionMessage = null, - [CallerMemberName] string testName = "") - where TContext : class - { - var (context, compiledModel) = base.Test( - onModelCreating, - assertModel, - useContext, - onConfiguring, - options, - addServices, - addDesignTimeServices, - expectedExceptionMessage, - testName); - - if (context == null - || compiledModel == null) - { - return (null, null); - } - - var relationalModel = (IRelationalModel)context.Model.FindRuntimeAnnotationValue(RelationalAnnotationNames.RelationalModel)!; - if (relationalModel != null) - { - // TODO: Move the asserts - //RelationalModelTest.AssertEqual(relationalModel, compiledModel.GetRelationalModel()); - } - - return (context, compiledModel); - } } diff --git a/test/EFCore.Relational.Specification.Tests/TestUtilities/RelationalModelAsserter.cs b/test/EFCore.Relational.Specification.Tests/TestUtilities/RelationalModelAsserter.cs new file mode 100644 index 00000000000..591c631aa06 --- /dev/null +++ b/test/EFCore.Relational.Specification.Tests/TestUtilities/RelationalModelAsserter.cs @@ -0,0 +1,1772 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.EntityFrameworkCore.Metadata.Internal; + +namespace Microsoft.EntityFrameworkCore.TestUtilities; + +public class RelationalModelAsserter : ModelAsserter +{ + public new static RelationalModelAsserter Instance { get; } = new(); + + public override void AssertEqual( + IReadOnlyModel expected, + IReadOnlyModel actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareMemberAnnotations = false) + { + base.AssertEqual( + expected, + actual, + expectedAnnotations.Where(a => !RelationalAnnotationNames.AllNames.Contains(a.Name)), + actualAnnotations.Where(a => !RelationalAnnotationNames.AllNames.Contains(a.Name)), + compareMemberAnnotations); + + var designTime = expected is Model && actual is Model; + + Assert.Multiple( + () => Assert.Equal(expected.GetDatabaseName(), actual.GetDatabaseName()), + () => Assert.Equal(expected.GetDefaultSchema(), actual.GetDefaultSchema()), + () => Assert.Equal(expected.GetMaxIdentifierLength(), actual.GetMaxIdentifierLength()), + () => + { + if (designTime) + { + Assert.Equal(expected.GetCollation(), actual.GetCollation()); + } + }, + () => Assert.Equal(expected.GetDbFunctions(), actual.GetDbFunctions(), + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations)), + () => Assert.Equal(expected.GetSequences(), actual.GetSequences(), + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations)), + () => + { + var expectedRelationalModel = (IRelationalModel)((IModel)expected) + ?.FindRuntimeAnnotationValue(RelationalAnnotationNames.RelationalModel); + var actualRelationalModel = (IRelationalModel)((IModel)actual) + ?.FindRuntimeAnnotationValue(RelationalAnnotationNames.RelationalModel); + if (expectedRelationalModel != null) + { + AssertEqual(expectedRelationalModel, actualRelationalModel, compareMemberAnnotations); + } + }); + } + + public virtual bool AssertEqual( + IReadOnlyDbFunction expected, + IReadOnlyDbFunction actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareBackreferences = false, + bool compareMemberAnnotations = false) + { + Assert.Same(actual, actual.Model.FindDbFunction(actual.ModelName)); + + Assert.Multiple( + () => Assert.Equal(expected.ModelName, actual.ModelName), + () => Assert.Equal(expected.Name, actual.Name), + () => Assert.Equal(expected.Schema, actual.Schema), + () => Assert.Equal(expected.ReturnType, actual.ReturnType), + () => Assert.Equal(expected.StoreType, actual.StoreType), + () => Assert.Equal(expected.IsBuiltIn, actual.IsBuiltIn), + () => Assert.Equal(expected.IsAggregate, actual.IsAggregate), + () => Assert.Equal(expected.IsScalar, actual.IsScalar), + () => Assert.Equal(expected.IsNullable, actual.IsNullable), + () => Assert.Equal(expected.MethodInfo, actual.MethodInfo), + () => Assert.Equal(expected.Translation, actual.Translation), + () => Assert.Equal(expected.TypeMapping?.StoreType, actual.TypeMapping?.StoreType), + () => Assert.Equal(expected.Parameters, actual.Parameters, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareBackreferences: false)), + () => Assert.Equal(((IRuntimeDbFunction)expected).StoreFunction.SchemaQualifiedName, + ((IRuntimeDbFunction)actual).StoreFunction.SchemaQualifiedName), + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + + return true; + } + + public virtual bool AssertEqual( + IReadOnlyDbFunctionParameter expected, + IReadOnlyDbFunctionParameter actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareBackreferences = false) + { + Assert.Multiple( + () => Assert.Equal(expected.Name, actual.Name), + () => + { + if (compareBackreferences) + { + Assert.Equal(expected.Function.ModelName, actual.Function.ModelName); + } + }, + () => Assert.Equal(expected.ClrType, actual.ClrType), + () => Assert.Equal(expected.StoreType, actual.StoreType), + () => Assert.Equal(expected.PropagatesNullability, actual.PropagatesNullability), + () => Assert.Equal(expected.TypeMapping?.StoreType, actual.TypeMapping?.StoreType), + () => Assert.Equal(((IRuntimeDbFunctionParameter)expected).StoreFunctionParameter.Name, + ((IRuntimeDbFunctionParameter)actual).StoreFunctionParameter.Name), + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + + return true; + } + + public virtual bool AssertEqual( + IReadOnlySequence expected, + IReadOnlySequence actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareBackreferences = false) + { + Assert.Same(actual, actual.Model.FindSequence(actual.Name, actual.ModelSchema)); + + Assert.Multiple( + () => Assert.Equal(expected.Name, actual.Name), + () => Assert.Equal(expected.Schema, actual.Schema), + () => Assert.Equal(expected.ModelSchema, actual.ModelSchema), + () => Assert.Equal(expected.Type, actual.Type), + () => Assert.Equal(expected.IncrementBy, actual.IncrementBy), + () => Assert.Equal(expected.StartValue, actual.StartValue), + () => Assert.Equal(expected.MaxValue, actual.MaxValue), + () => Assert.Equal(expected.MinValue, actual.MinValue), + () => Assert.Equal(expected.IsCyclic, actual.IsCyclic), + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + + return true; + } + + public override bool AssertEqual( + IReadOnlyEntityType expected, + IReadOnlyEntityType actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareBackreferences = false, + bool compareMemberAnnotations = false) + { + base.AssertEqual( + expected, + actual, + expectedAnnotations.Where(a => !RelationalAnnotationNames.AllNames.Contains(a.Name)), + actualAnnotations.Where(a => !RelationalAnnotationNames.AllNames.Contains(a.Name)), + compareBackreferences, + compareMemberAnnotations); + + if (expected is not ITypeBase expectedStructuralType + || actual is not ITypeBase actualStructuralType) + { + return true; + } + + var designTime = expected is EntityType && actual is EntityType; + + Assert.Multiple( + () => Assert.Equal(expected.GetDbSetName(), actual.GetDbSetName()), + () => Assert.Equal(expected.GetContainerColumnName(), actual.GetContainerColumnName()), + () => Assert.Equal(expected.GetJsonPropertyName(), actual.GetJsonPropertyName()), + () => + { + if (designTime) + { + Assert.Equal(expected.GetComment(), actual.GetComment()); + } + }, + () => + { + if (designTime) + { + Assert.Equal(expected.IsTableExcludedFromMigrations(), actual.IsTableExcludedFromMigrations()); + } + }, + () => Assert.Equal(expected.GetSchemaQualifiedTableName(), actual.GetSchemaQualifiedTableName()), + () => Assert.Equal(expected.GetSchemaQualifiedViewName(), actual.GetSchemaQualifiedViewName()), + () => Assert.Equal(expected.GetSqlQuery(), actual.GetSqlQuery()), + () => Assert.Equal(expected.GetFunctionName(), actual.GetFunctionName()), + () => AssertEqual( + expected.GetInsertStoredProcedure(), + actual.GetInsertStoredProcedure(), + compareBackreferences: false, + compareMemberAnnotations), + () => AssertEqual( + expected.GetUpdateStoredProcedure(), + actual.GetUpdateStoredProcedure(), + compareBackreferences: false, + compareMemberAnnotations), + () => AssertEqual( + expected.GetDeleteStoredProcedure(), + actual.GetDeleteStoredProcedure(), + compareBackreferences: false, + compareMemberAnnotations), + () => Assert.Equal(expected.GetMappingFragments(), actual.GetMappingFragments(), + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareBackreferences: false)), + () => + { + if (designTime) + { + Assert.Equal(expected.GetCheckConstraints(), actual.GetCheckConstraints(), + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareBackreferences: false)); + } + }, + () => Assert.Equal(expectedStructuralType.GetDefaultMappings(), actualStructuralType.GetDefaultMappings(), + (expected, actual) => + { + Assert.Equal(expected.Table.SchemaQualifiedName, actual.Table.SchemaQualifiedName); + return true; + }), + () => Assert.Equal(expectedStructuralType.GetTableMappings(), actualStructuralType.GetTableMappings(), + (expected, actual) => + { + Assert.Equal(expected.Table.SchemaQualifiedName, actual.Table.SchemaQualifiedName); + return true; + }), + () => Assert.Equal(expectedStructuralType.GetViewMappings(), actualStructuralType.GetViewMappings(), + (expected, actual) => + { + Assert.Equal(expected.Table.SchemaQualifiedName, actual.Table.SchemaQualifiedName); + return true; + }), + () => Assert.Equal(expectedStructuralType.GetSqlQueryMappings(), actualStructuralType.GetSqlQueryMappings(), + (expected, actual) => + { + Assert.Equal(expected.Table.SchemaQualifiedName, actual.Table.SchemaQualifiedName); + return true; + }), + () => Assert.Equal(expectedStructuralType.GetFunctionMappings(), actualStructuralType.GetFunctionMappings(), + (expected, actual) => + { + Assert.Equal(expected.Table.SchemaQualifiedName, actual.Table.SchemaQualifiedName); + return true; + }), + () => Assert.Equal(expectedStructuralType.GetInsertStoredProcedureMappings(), actualStructuralType.GetInsertStoredProcedureMappings(), + (expected, actual) => + { + Assert.Equal(expected.Table.SchemaQualifiedName, actual.Table.SchemaQualifiedName); + return true; + }), + () => Assert.Equal(expectedStructuralType.GetUpdateStoredProcedureMappings(), actualStructuralType.GetUpdateStoredProcedureMappings(), + (expected, actual) => + { + Assert.Equal(expected.Table.SchemaQualifiedName, actual.Table.SchemaQualifiedName); + return true; + }), + () => Assert.Equal(expectedStructuralType.GetDeleteStoredProcedureMappings(), actualStructuralType.GetDeleteStoredProcedureMappings(), + (expected, actual) => + { + Assert.Equal(expected.Table.SchemaQualifiedName, actual.Table.SchemaQualifiedName); + return true; + })); + + return true; + } + + public virtual bool AssertEqual( + IReadOnlyEntityTypeMappingFragment expected, + IReadOnlyEntityTypeMappingFragment actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareBackreferences = false) + { + expectedAnnotations = expectedAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); + actualAnnotations = actualAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); + + Assert.Multiple( + () => Assert.Equal(expected.IsTableExcludedFromMigrations, actual.IsTableExcludedFromMigrations), + () => Assert.Equal(expected.StoreObject, actual.StoreObject), + () => + { + if (compareBackreferences) + { + Assert.Equal(expected.EntityType, actual.EntityType, EntityTypeFullNameComparer.Instance); + } + }, + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + + return true; + } + + public virtual bool AssertEqual( + IReadOnlyStoredProcedure expected, + IReadOnlyStoredProcedure actual, + bool compareBackreferences = false, + bool compareAnnotations = false) + { + if (expected == null) + { + Assert.Null(actual); + return true; + } + + var expectedAnnotations = compareAnnotations ? expected.GetAnnotations() : Enumerable.Empty(); + var actualAnnotations = compareAnnotations ? actual.GetAnnotations() : Enumerable.Empty(); + + Assert.Multiple( + () => Assert.Equal(expected.Name, actual.Name), + () => Assert.Equal(expected.GetStoreIdentifier(), actual.GetStoreIdentifier()), + () => Assert.Equal(expected.IsRowsAffectedReturned, actual.IsRowsAffectedReturned), + () => + { + if (compareBackreferences) + { + Assert.Equal(expected.EntityType, actual.EntityType, EntityTypeFullNameComparer.Instance); + } + }, + () => Assert.Equal(expected.Parameters, actual.Parameters, + (expected, actual) => + AssertEqual( + expected, + actual, + compareAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareBackreferences: false, + compareAnnotations)), + () => Assert.Equal(expected.ResultColumns, actual.ResultColumns, + (expected, actual) => + AssertEqual( + expected, + actual, + compareAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareBackreferences: false, + compareAnnotations)), + () => Assert.Equal(((IRuntimeStoredProcedure)expected).StoreStoredProcedure.SchemaQualifiedName, + ((IRuntimeStoredProcedure)actual).StoreStoredProcedure.SchemaQualifiedName), + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + + return true; + } + + public virtual bool AssertEqual( + IReadOnlyStoredProcedureParameter expected, + IReadOnlyStoredProcedureParameter actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareBackreferences = false, + bool compareMemberAnnotations = false) + { + Assert.Multiple( + () => Assert.Equal(expected.Name, actual.Name), + () => Assert.Equal(expected.PropertyName, actual.PropertyName), + () => Assert.Equal(expected.Direction, actual.Direction), + () => Assert.Equal(expected.ForOriginalValue, actual.ForOriginalValue), + () => Assert.Equal(expected.ForRowsAffected, actual.ForRowsAffected), + () => + { + if (compareBackreferences) + { + Assert.Equal(expected.StoredProcedure.Name, actual.StoredProcedure.Name); + } + }, + () => Assert.Equal(((IRuntimeStoredProcedureParameter)expected).StoreParameter.Name, + ((IRuntimeStoredProcedureParameter)actual).StoreParameter.Name), + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + + return true; + } + + public virtual bool AssertEqual( + IReadOnlyStoredProcedureResultColumn expected, + IReadOnlyStoredProcedureResultColumn actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareBackreferences = false, + bool compareMemberAnnotations = false) + { + Assert.Multiple( + () => Assert.Equal(expected.Name, actual.Name), + () => Assert.Equal(expected.PropertyName, actual.PropertyName), + () => Assert.Equal(expected.ForRowsAffected, actual.ForRowsAffected), + () => + { + if (compareBackreferences) + { + Assert.Equal(expected.StoredProcedure.Name, actual.StoredProcedure.Name); + } + }, + () => Assert.Equal(((IRuntimeStoredProcedureResultColumn)expected).StoreResultColumn.Name, + ((IRuntimeStoredProcedureResultColumn)actual).StoreResultColumn.Name), + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + + + return true; + } + + public virtual bool AssertEqual( + IReadOnlyCheckConstraint expected, + IReadOnlyCheckConstraint actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareBackreferences = false) + { + Assert.Same(actual, actual.EntityType.FindCheckConstraint(actual.ModelName)); + + Assert.Multiple( + () => Assert.Equal(expected.Name, actual.Name), + () => Assert.Equal(expected.ModelName, actual.ModelName), + () => Assert.Equal(expected.Sql, actual.Sql), + () => + { + if (compareBackreferences) + { + Assert.Equal(expected.EntityType, actual.EntityType, EntityTypeFullNameComparer.Instance); + } + }, + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + + return true; + } + + public override bool AssertEqual( + IReadOnlyComplexType expected, + IReadOnlyComplexType actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareBackreferences = false, + bool compareMemberAnnotations = false) + { + base.AssertEqual( + expected, + actual, + expectedAnnotations, + actualAnnotations, + compareBackreferences, + compareMemberAnnotations); + + if (expected is not ITypeBase expectedStructuralType + || actual is not ITypeBase actualStructuralType) + { + return true; + } + + Assert.Multiple( + () => Assert.Equal(expected.GetContainerColumnName(), actual.GetContainerColumnName()), + () => Assert.Equal(expectedStructuralType.GetJsonPropertyName(), actualStructuralType.GetJsonPropertyName()), + () => Assert.Equal(expectedStructuralType.GetTableName(), actualStructuralType.GetTableName()), + () => Assert.Equal(expectedStructuralType.GetViewName(), actualStructuralType.GetViewName()), + () => Assert.Equal(expectedStructuralType.GetSqlQuery(), actualStructuralType.GetSqlQuery()), + () => Assert.Equal(expectedStructuralType.GetFunctionName(), actualStructuralType.GetFunctionName()), + () => AssertEqual( + expectedStructuralType.GetInsertStoredProcedure(), + actualStructuralType.GetInsertStoredProcedure(), + compareBackreferences: false, + compareMemberAnnotations), + () => AssertEqual( + expectedStructuralType.GetUpdateStoredProcedure(), + actualStructuralType.GetUpdateStoredProcedure(), + compareBackreferences: false, + compareMemberAnnotations), + () => AssertEqual( + expectedStructuralType.GetDeleteStoredProcedure(), + actualStructuralType.GetDeleteStoredProcedure(), + compareBackreferences: false, + compareMemberAnnotations), + () => Assert.Equal(expectedStructuralType.GetMappingFragments(), actualStructuralType.GetMappingFragments(), + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareBackreferences: false)), + () => Assert.Equal(expectedStructuralType.GetDefaultMappings(), actualStructuralType.GetDefaultMappings(), + (expected, actual) => + { + Assert.Equal(expected.Table.SchemaQualifiedName, actual.Table.SchemaQualifiedName); + return true; + }), + () => Assert.Equal(expectedStructuralType.GetTableMappings(), actualStructuralType.GetTableMappings(), + (expected, actual) => + { + Assert.Equal(expected.Table.SchemaQualifiedName, actual.Table.SchemaQualifiedName); + return true; + }), + () => Assert.Equal(expectedStructuralType.GetViewMappings(), actualStructuralType.GetViewMappings(), + (expected, actual) => + { + Assert.Equal(expected.Table.SchemaQualifiedName, actual.Table.SchemaQualifiedName); + return true; + }), + () => Assert.Equal(expectedStructuralType.GetSqlQueryMappings(), actualStructuralType.GetSqlQueryMappings(), + (expected, actual) => + { + Assert.Equal(expected.Table.SchemaQualifiedName, actual.Table.SchemaQualifiedName); + return true; + }), + () => Assert.Equal(expectedStructuralType.GetFunctionMappings(), actualStructuralType.GetFunctionMappings(), + (expected, actual) => + { + Assert.Equal(expected.Table.SchemaQualifiedName, actual.Table.SchemaQualifiedName); + return true; + }), + () => Assert.Equal(expectedStructuralType.GetInsertStoredProcedureMappings(), actualStructuralType.GetInsertStoredProcedureMappings(), + (expected, actual) => + { + Assert.Equal(expected.Table.SchemaQualifiedName, actual.Table.SchemaQualifiedName); + return true; + }), + () => Assert.Equal(expectedStructuralType.GetUpdateStoredProcedureMappings(), actualStructuralType.GetUpdateStoredProcedureMappings(), + (expected, actual) => + { + Assert.Equal(expected.Table.SchemaQualifiedName, actual.Table.SchemaQualifiedName); + return true; + }), + () => Assert.Equal(expectedStructuralType.GetDeleteStoredProcedureMappings(), actualStructuralType.GetDeleteStoredProcedureMappings(), + (expected, actual) => + { + Assert.Equal(expected.Table.SchemaQualifiedName, actual.Table.SchemaQualifiedName); + return true; + })); + + return true; + } + + public override bool AssertEqual( + IReadOnlyProperty expected, + IReadOnlyProperty actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareBackreferences = false, + bool compareMemberAnnotations = false) + { + base.AssertEqual( + expected, + actual, + expectedAnnotations.Where(a => !RelationalAnnotationNames.AllNames.Contains(a.Name)), + actualAnnotations.Where(a => !RelationalAnnotationNames.AllNames.Contains(a.Name)), + compareBackreferences); + + if (expected is not IProperty expectedProperty + || actual is not IProperty actualProperty) + { + return true; + } + + var designTime = expected is Property && actual is Property; + + Assert.Multiple( + () => Assert.Equal(expected.GetColumnType(), actual.GetColumnType()), + () => Assert.Equal(expected.GetColumnName(), actual.GetColumnName()), + () => Assert.Equal(expected.GetIsStored(), actual.GetIsStored()), + () => Assert.Equal(expected.GetJsonPropertyName(), actual.GetJsonPropertyName()), + () => Assert.Equal(expected.IsOrdinalKeyProperty(), actual.IsOrdinalKeyProperty()), + () => + { + if (designTime) + { + Assert.Equal(expected.GetColumnOrder(), actual.GetColumnOrder()); + } + }, + () => Assert.Equal(expected.GetComputedColumnSql(), actual.GetComputedColumnSql()), + () => Assert.Equal(expected.GetDefaultValueSql(), actual.GetDefaultValueSql()), + () => Assert.Equal(expected.GetDefaultValue(), actual.GetDefaultValue()), + () => Assert.Equal(expected.IsFixedLength(), actual.IsFixedLength()), + () => Assert.Equal(expected.GetMaxLength(), actual.GetMaxLength()), + () => Assert.Equal(expected.GetScale(), actual.GetScale()), + () => Assert.Equal(expected.GetPrecision(), actual.GetPrecision()), + () => Assert.Equal(expected.IsColumnNullable(), actual.IsColumnNullable()), + () => + { + if (designTime) + { + Assert.Equal(expected.GetComment(), actual.GetComment()); + } + }, + () => + { + if (designTime) + { + Assert.Equal(expected.GetCollation(), actual.GetCollation()); + } + }, + () => Assert.Equal(expected.GetOverrides(), actual.GetOverrides(), + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty())), + () => Assert.Equal(expectedProperty.GetDefaultColumnMappings().ToList(), actualProperty.GetDefaultColumnMappings(), + (expected, actual) => + { + Assert.Equal(expected.Column.Table.SchemaQualifiedName, actual.Column.Table.SchemaQualifiedName); + return true; + }), + () => Assert.Equal(expectedProperty.GetTableColumnMappings().ToList(), actualProperty.GetTableColumnMappings(), + (expected, actual) => + { + Assert.Equal(expected.Column.Table.SchemaQualifiedName, actual.Column.Table.SchemaQualifiedName); + return true; + }), + () => Assert.Equal(expectedProperty.GetViewColumnMappings().ToList(), actualProperty.GetViewColumnMappings(), + (expected, actual) => + { + Assert.Equal(expected.Column.Table.SchemaQualifiedName, actual.Column.Table.SchemaQualifiedName); + return true; + }), + () => Assert.Equal(expectedProperty.GetSqlQueryColumnMappings().ToList(), actualProperty.GetSqlQueryColumnMappings(), + (expected, actual) => + { + Assert.Equal(expected.Column.Table.SchemaQualifiedName, actual.Column.Table.SchemaQualifiedName); + return true; + }), + () => Assert.Equal(expectedProperty.GetFunctionColumnMappings().ToList(), actualProperty.GetFunctionColumnMappings(), + (expected, actual) => + { + Assert.Equal(expected.Column.Table.SchemaQualifiedName, actual.Column.Table.SchemaQualifiedName); + return true; + }), + () => Assert.Equal(expectedProperty.GetInsertStoredProcedureParameterMappings().ToList(), actualProperty.GetInsertStoredProcedureParameterMappings(), + (expected, actual) => + { + Assert.Equal(expected.Column.Table.SchemaQualifiedName, actual.Column.Table.SchemaQualifiedName); + return true; + }), + () => Assert.Equal(expectedProperty.GetInsertStoredProcedureResultColumnMappings().ToList(), actualProperty.GetInsertStoredProcedureResultColumnMappings(), + (expected, actual) => + { + Assert.Equal(expected.Column.Table.SchemaQualifiedName, actual.Column.Table.SchemaQualifiedName); + return true; + }), + () => Assert.Equal(expectedProperty.GetUpdateStoredProcedureParameterMappings().ToList(), actualProperty.GetUpdateStoredProcedureParameterMappings(), + (expected, actual) => + { + Assert.Equal(expected.Column.Table.SchemaQualifiedName, actual.Column.Table.SchemaQualifiedName); + return true; + }), + () => Assert.Equal(expectedProperty.GetUpdateStoredProcedureResultColumnMappings().ToList(), actualProperty.GetUpdateStoredProcedureResultColumnMappings(), + (expected, actual) => + { + Assert.Equal(expected.Column.Table.SchemaQualifiedName, actual.Column.Table.SchemaQualifiedName); + return true; + }), + () => Assert.Equal(expectedProperty.GetDeleteStoredProcedureParameterMappings().ToList(), actualProperty.GetDeleteStoredProcedureParameterMappings(), + (expected, actual) => + { + Assert.Equal(expected.Column.Table.SchemaQualifiedName, actual.Column.Table.SchemaQualifiedName); + return true; + })); + + return true; + } + + public virtual bool AssertEqual( + IReadOnlyRelationalPropertyOverrides expected, + IReadOnlyRelationalPropertyOverrides actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations) + { + expectedAnnotations = expectedAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); + actualAnnotations = actualAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); + + Assert.Multiple( + () => Assert.Equal(expected.StoreObject, actual.StoreObject), + () => Assert.Equal(expected.ColumnName, actual.ColumnName), + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + + return true; + } + + public override bool AssertEqual( + IReadOnlyForeignKey expected, + IReadOnlyForeignKey actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareBackreferences = false, + bool compareMemberAnnotations = false) + { + base.AssertEqual( + expected, + actual, + expectedAnnotations.Where(a => !RelationalAnnotationNames.AllNames.Contains(a.Name)), + actualAnnotations.Where(a => !RelationalAnnotationNames.AllNames.Contains(a.Name)), + compareBackreferences, + compareMemberAnnotations); + + if (expected is not IForeignKey expectedForeignKey + || actual is not IForeignKey actualForeignKey) + { + return true; + } + + Assert.Multiple( + () => Assert.Equal(expected.GetConstraintName(), actual.GetConstraintName()), + () => Assert.Equal(expectedForeignKey.GetMappedConstraints().ToList(), actualForeignKey.GetMappedConstraints(), + (expected, actual) => + { + Assert.Equal(expected.Table.SchemaQualifiedName, actual.Table.SchemaQualifiedName); + return true; + })); + + return true; + } + + public override bool AssertEqual( + IReadOnlyIndex expected, + IReadOnlyIndex actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareBackreferences = false, + bool compareMemberAnnotations = false) + { + base.AssertEqual( + expected, + actual, + expectedAnnotations.Where(a => !RelationalAnnotationNames.AllNames.Contains(a.Name)), + actualAnnotations.Where(a => !RelationalAnnotationNames.AllNames.Contains(a.Name)), + compareBackreferences); + + if (expected is not IIndex expectedIndex + || actual is not IIndex actualIndex) + { + return true; + } + + Assert.Multiple( + () => Assert.Equal(expected.GetDatabaseName(), actual.GetDatabaseName()), + () => Assert.Equal(expected.GetFilter(), actual.GetFilter()), + () => Assert.Equal(expectedIndex.GetMappedTableIndexes().ToList(), actualIndex.GetMappedTableIndexes(), + (expected, actual) => + { + Assert.Equal(expected.Table.SchemaQualifiedName, actual.Table.SchemaQualifiedName); + return true; + })); + + return true; + } + + public override bool AssertEqual( + IReadOnlyKey expected, + IReadOnlyKey actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareBackreferences = false, + bool compareMemberAnnotations = false) + { + base.AssertEqual( + expected, + actual, + expectedAnnotations.Where(a => !RelationalAnnotationNames.AllNames.Contains(a.Name)), + actualAnnotations.Where(a => !RelationalAnnotationNames.AllNames.Contains(a.Name)), + compareBackreferences); + + if (expected is not IKey expectedKey + || actual is not IKey actualKey) + { + return true; + } + + Assert.Multiple( + () => Assert.Equal(expected.GetName(), actual.GetName()), + () => Assert.Equal(expectedKey.GetMappedConstraints().ToList(), actualKey.GetMappedConstraints(), + (expected, actual) => + { + Assert.Equal(expected.Table.SchemaQualifiedName, actual.Table.SchemaQualifiedName); + return true; + })); + + return true; + } + + public virtual void AssertEqual( + IRelationalModel expected, + IRelationalModel actual, + bool compareAnnotations = false) + => AssertEqual( + expected, + actual, + compareAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations: compareAnnotations); + + public virtual void AssertEqual( + IRelationalModel expected, + IRelationalModel actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareMemberAnnotations = true) + { + if (expected is not RelationalModel expectedModel + || actual is not RelationalModel actualModel) + { + return; + } + + var designTime = expected.Model is Model && actual.Model is Model; + + Assert.Multiple( + () => Assert.Equal(expectedModel.IsReadOnly, actualModel.IsReadOnly), + () => + { + if (designTime) + { + Assert.Equal(expected.Collation, actual.Collation); + } + }, + () => Assert.Equal(expectedModel.DefaultTables.Values, actualModel.DefaultTables.Values, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations)), + () => Assert.Equal(expected.Tables, actual.Tables, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations)), + () => Assert.Equal(expected.Views, actual.Views, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations)), + () => Assert.Equal(expected.Queries, actual.Queries, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations)), + () => Assert.Equal(expected.Functions, actual.Functions, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations)), + () => Assert.Equal(expected.StoredProcedures, actual.StoredProcedures, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations)), + () => Assert.Equal(expected.Sequences, actual.Sequences, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations)), + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + } + + public virtual bool AssertEqualBase( + ITableBase expected, + ITableBase actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareMemberAnnotations) + { + Assert.Multiple( + () => Assert.Equal(expected.Name, actual.Name), + () => Assert.Equal(expected.Schema, actual.Schema), + () => Assert.Equal(expected.IsShared, actual.IsShared), + () => + { + foreach (IEntityType expectedEntityType in expected.EntityTypeMappings.Select(m => m.TypeBase)) + { + var actualEntityType = + (IEntityType)actual.EntityTypeMappings.Single(m => m.TypeBase.Name == expectedEntityType.Name).TypeBase; + Assert.Equal( + expected.GetRowInternalForeignKeys(expectedEntityType).Count(), + actual.GetRowInternalForeignKeys(actualEntityType).Count()); + Assert.Equal( + expected.GetReferencingRowInternalForeignKeys(expectedEntityType).Count(), + actual.GetReferencingRowInternalForeignKeys(actualEntityType).Count()); + } + }, + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + + return true; + } + + public virtual bool AssertEqual( + ITableBase expected, + ITableBase actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareMemberAnnotations) + { + Assert.Multiple( + () => AssertEqualBase(expected, actual, expectedAnnotations, actualAnnotations, compareMemberAnnotations), + () => Assert.Same(actual, ((RelationalModel)actual.Model).DefaultTables[actual.Name]), + () => Assert.Equal(expected.Columns, actual.Columns, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations)), + () => Assert.Equal(expected.EntityTypeMappings.ToList(), actual.EntityTypeMappings, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations)), + () => Assert.Equal(expected.ComplexTypeMappings.ToList(), actual.ComplexTypeMappings, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations))); + + return true; + } + + public virtual bool AssertEqual( + ITable expected, + ITable actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareMemberAnnotations) + { + Assert.Multiple( + () => AssertEqualBase(expected, actual, expectedAnnotations, actualAnnotations, compareMemberAnnotations), + () => Assert.Same(actual, actual.Model.FindTable(actual.Name, actual.Schema)), + () => Assert.Equal(expected.Columns, actual.Columns, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations)), + () => Assert.Equal(expected.Indexes, actual.Indexes, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty())), + () => Assert.Equal(expected.ForeignKeyConstraints.ToList(), actual.ForeignKeyConstraints, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty())), + () => Assert.Equal(expected.ReferencingForeignKeyConstraints.ToList(), actual.ReferencingForeignKeyConstraints, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty())), + () => Assert.Equal(expected.UniqueConstraints, actual.UniqueConstraints, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty())), + () => Assert.Equal(expected.Triggers, actual.Triggers, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty())), + () => Assert.Equal(expected.EntityTypeMappings.ToList(), actual.EntityTypeMappings, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations)), + () => Assert.Equal(expected.ComplexTypeMappings.ToList(), actual.ComplexTypeMappings, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations))); + + return true; + } + + public virtual bool AssertEqual( + IView expected, + IView actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareMemberAnnotations) + { + Assert.Multiple( + () => AssertEqualBase(expected, actual, expectedAnnotations, actualAnnotations, compareMemberAnnotations), + () => Assert.Same(actual, actual.Model.FindView(actual.Name, actual.Schema)), + () => Assert.Equal(expected.Columns, actual.Columns, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations)), + () => Assert.Equal(expected.EntityTypeMappings.ToList(), actual.EntityTypeMappings, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations)), + () => Assert.Equal(expected.ComplexTypeMappings.ToList(), actual.ComplexTypeMappings, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations))); + + return true; + } + + public virtual bool AssertEqual( + ISqlQuery expected, + ISqlQuery actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareMemberAnnotations) + { + Assert.Multiple( + () => AssertEqualBase(expected, actual, expectedAnnotations, actualAnnotations, compareMemberAnnotations), + () => Assert.Equal(expected.Sql, actual.Sql), + () => Assert.Same(actual, actual.Model.FindQuery(actual.Name)), + () => Assert.Equal(expected.Columns, actual.Columns, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations)), + () => Assert.Equal(expected.EntityTypeMappings.ToList(), actual.EntityTypeMappings, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations)), + () => Assert.Equal(expected.ComplexTypeMappings.ToList(), actual.ComplexTypeMappings, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations))); + + return true; + } + + public virtual bool AssertEqual( + IStoreFunction expected, + IStoreFunction actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareMemberAnnotations) + { + Assert.Multiple( + () => AssertEqualBase(expected, actual, expectedAnnotations, actualAnnotations, compareMemberAnnotations), + () => Assert.Equal(expected.ReturnType, actual.ReturnType), + () => Assert.Equal(expected.IsBuiltIn, actual.IsBuiltIn), + () => Assert.Same( + actual, actual.Model.FindFunction(actual.Name, actual.Schema, actual.Parameters.Select(p => p.StoreType).ToArray())), + () => Assert.Equal( + actual.DbFunctions.Select(p => p.ModelName), + expected.DbFunctions.Select(p => p.ModelName)), + () => Assert.Equal(expected.Parameters, actual.Parameters, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations)), + () => Assert.Equal(expected.Columns, actual.Columns, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations)), + () => Assert.Equal(expected.EntityTypeMappings.ToList(), actual.EntityTypeMappings, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations)), + () => Assert.Equal(expected.ComplexTypeMappings.ToList(), actual.ComplexTypeMappings, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations))); + + return true; + } + + public virtual bool AssertEqual( + IStoreStoredProcedure expected, + IStoreStoredProcedure actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareMemberAnnotations) + { + Assert.Multiple( + () => AssertEqualBase(expected, actual, expectedAnnotations, actualAnnotations, compareMemberAnnotations), + () => Assert.Same(actual, actual.Model.FindStoredProcedure(actual.Name, actual.Schema)), + () => Assert.Equal( + actual.StoredProcedures.Select(p => p.Name), + expected.StoredProcedures.Select(p => p.Name)), + () => + { + if (expected.ReturnValue != null) + { + AssertEqualBase( + expected.ReturnValue, + actual.ReturnValue, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty()); + Assert.Same(actual, actual.ReturnValue.StoredProcedure); + Assert.Equal(expected.ReturnValue.PropertyMappings, actual.ReturnValue.PropertyMappings, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty())); + } + else + { + Assert.Null(actual.ReturnValue); + } + }, + () => Assert.Equal(expected.Parameters, actual.Parameters, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations)), + () => Assert.Equal(expected.ResultColumns, actual.ResultColumns, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations)), + () => Assert.Equal(expected.EntityTypeMappings.ToList(), actual.EntityTypeMappings, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations)), + () => Assert.Equal(expected.ComplexTypeMappings.ToList(), actual.ComplexTypeMappings, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations))); + + return true; + } + + public virtual bool AssertEqualBase( + ITableMappingBase expected, + ITableMappingBase actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations) + { + Assert.Multiple( + () => Assert.Equal(expected.TypeBase.Name, actual.TypeBase.Name), + () => Assert.Equal(expected.Table.SchemaQualifiedName, actual.Table.SchemaQualifiedName), + () => Assert.Equal(expected.IncludesDerivedTypes, actual.IncludesDerivedTypes), + () => Assert.Equal(expected.IsSharedTablePrincipal, actual.IsSharedTablePrincipal), + () => Assert.Equal(expected.IsSplitEntityTypePrincipal, actual.IsSplitEntityTypePrincipal), + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + + return true; + } + + public virtual bool AssertEqual( + ITableMappingBase expected, + ITableMappingBase actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareMemberAnnotations) + { + Assert.Multiple( + () => AssertEqualBase(expected, actual, expectedAnnotations, actualAnnotations), + () => Assert.Equal(expected.ColumnMappings, actual.ColumnMappings, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty()))); + + return true; + } + + public virtual bool AssertEqual( + ITableMapping expected, + ITableMapping actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareMemberAnnotations) + { + Assert.Multiple( + () => AssertEqualBase(expected, actual, expectedAnnotations, actualAnnotations), + () => AssertEqual(expected.DeleteStoredProcedureMapping, actual.DeleteStoredProcedureMapping, compareMemberAnnotations), + () => AssertEqual(expected.InsertStoredProcedureMapping, actual.InsertStoredProcedureMapping, compareMemberAnnotations), + () => AssertEqual(expected.UpdateStoredProcedureMapping, actual.UpdateStoredProcedureMapping, compareMemberAnnotations), + () => Assert.Equal(expected.ColumnMappings, actual.ColumnMappings, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty()))); + + return true; + } + + public virtual bool AssertEqual( + IViewMapping expected, + IViewMapping actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareMemberAnnotations) + { + Assert.Multiple( + () => AssertEqualBase(expected, actual, expectedAnnotations, actualAnnotations), + () => Assert.Equal(expected.ColumnMappings, actual.ColumnMappings, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty()))); + + return true; + } + + public virtual bool AssertEqual( + ISqlQueryMapping expected, + ISqlQueryMapping actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareMemberAnnotations) + { + Assert.Multiple( + () => AssertEqualBase(expected, actual, expectedAnnotations, actualAnnotations), + () => Assert.Equal(expected.IsDefaultSqlQueryMapping, actual.IsDefaultSqlQueryMapping), + () => Assert.Equal(expected.ColumnMappings, actual.ColumnMappings, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty()))); + + return true; + } + + public virtual bool AssertEqual( + IFunctionMapping expected, + IFunctionMapping actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareMemberAnnotations) + { + Assert.Multiple( + () => AssertEqualBase(expected, actual, expectedAnnotations, actualAnnotations), + () => Assert.Equal(expected.IsDefaultFunctionMapping, actual.IsDefaultFunctionMapping), + () => Assert.Equal(expected.ColumnMappings, actual.ColumnMappings, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty()))); + + return true; + } + + public virtual bool AssertEqual( + IStoredProcedureMapping expected, + IStoredProcedureMapping actual, + bool compareMemberAnnotations) + { + if (expected == null) + { + Assert.Null(actual); + return true; + } + + return AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations); + } + + public virtual bool AssertEqual( + IStoredProcedureMapping expected, + IStoredProcedureMapping actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareMemberAnnotations) + { + Assert.Multiple( + () => AssertEqualBase(expected, actual, expectedAnnotations, actualAnnotations), + () => Assert.Equal(expected.StoredProcedure.GetSchemaQualifiedName(), actual.StoredProcedure.GetSchemaQualifiedName()), + () => Assert.Contains(expected.TableMapping?.Table.SchemaQualifiedName, actual.TableMapping?.Table.SchemaQualifiedName), + () => Assert.Equal(expected.ResultColumnMappings, actual.ResultColumnMappings, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty())), + () => Assert.Equal(expected.ParameterMappings, actual.ParameterMappings, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty()))); + + return true; + } + + public virtual bool AssertEqualBase( + IColumnBase expected, + IColumnBase actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations) + { + Assert.Multiple( + () => Assert.Equal(expected.Name, actual.Name), + () => Assert.Equal(expected.IsNullable, actual.IsNullable), + () => Assert.Equal(expected.ProviderClrType, actual.ProviderClrType), + () => Assert.Equal(expected.StoreType, actual.StoreType), + () => Assert.Equal(expected.StoreTypeMapping.StoreType, actual.StoreTypeMapping.StoreType), + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + + return true; + } + + public virtual bool AssertEqual( + IColumnBase expected, + IColumnBase actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareMemberAnnotations) + { + Assert.Multiple( + () => AssertEqualBase(expected, actual, expectedAnnotations, actualAnnotations), + () => Assert.Same(actual, actual.Table.FindColumn(actual.Name)), + () => Assert.Equal(expected.PropertyMappings, actual.PropertyMappings, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty()))); + + return true; + } + + public virtual bool AssertEqual( + IColumn expected, + IColumn actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareMemberAnnotations) + { + Assert.Multiple( + () => AssertEqualBase(expected, actual, expectedAnnotations, actualAnnotations), + () => Assert.Same(actual, actual.Table.FindColumn(actual.Name)), + () => Assert.Equal(expected.PropertyMappings, actual.PropertyMappings, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty()))); + + return true; + } + + public virtual bool AssertEqual( + IViewColumn expected, + IViewColumn actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareMemberAnnotations) + { + Assert.Multiple( + () => AssertEqualBase(expected, actual, expectedAnnotations, actualAnnotations), + () => Assert.Same(actual, actual.View.FindColumn(actual.Name)), + () => Assert.Equal(expected.PropertyMappings, actual.PropertyMappings, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty()))); + + return true; + } + + public virtual bool AssertEqual( + ISqlQueryColumn expected, + ISqlQueryColumn actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareMemberAnnotations) + { + Assert.Multiple( + () => AssertEqualBase(expected, actual, expectedAnnotations, actualAnnotations), + () => Assert.Same(actual, actual.SqlQuery.FindColumn(actual.Name)), + () => Assert.Equal(expected.PropertyMappings, actual.PropertyMappings, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty()))); + + return true; + } + + public virtual bool AssertEqual( + IFunctionColumn expected, + IFunctionColumn actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareMemberAnnotations) + { + Assert.Multiple( + () => AssertEqualBase(expected, actual, expectedAnnotations, actualAnnotations), + () => Assert.Same(actual, actual.Function.FindColumn(actual.Name)), + () => Assert.Equal(expected.PropertyMappings, actual.PropertyMappings, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty()))); + + return true; + } + + public virtual bool AssertEqual( + IStoreFunctionParameter expected, + IStoreFunctionParameter actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareMemberAnnotations) + { + Assert.Multiple( + () => Assert.Equal(expected.Name, actual.Name), + () => Assert.Equal(expected.StoreType, actual.StoreType), + () => Assert.Contains(actual, actual.Function.Parameters), + () => Assert.Equal(expected.DbFunctionParameters, actual.DbFunctionParameters, + (expected, actual) => + { + Assert.Equal(expected.Name, actual.Name); + return true; + }), + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + + return true; + } + + public virtual bool AssertEqual( + IStoreStoredProcedureResultColumn expected, + IStoreStoredProcedureResultColumn actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareMemberAnnotations) + { + Assert.Multiple( + () => AssertEqualBase(expected, actual, expectedAnnotations, actualAnnotations), + () => Assert.Equal(expected.Position, actual.Position), + () => Assert.Same(actual, actual.StoredProcedure.FindResultColumn(actual.Name)), + () => Assert.Equal(expected.PropertyMappings, actual.PropertyMappings, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty()))); + + return true; + } + + public virtual bool AssertEqual( + IStoreStoredProcedureParameter expected, + IStoreStoredProcedureParameter actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareMemberAnnotations) + { + Assert.Multiple( + () => AssertEqualBase(expected, actual, expectedAnnotations, actualAnnotations), + () => Assert.Equal(expected.Position, actual.Position), + () => Assert.Equal(expected.Direction, actual.Direction), + () => Assert.Same(actual, actual.StoredProcedure.FindParameter(actual.Name)), + () => Assert.Equal(expected.PropertyMappings, actual.PropertyMappings, + (expected, actual) => + AssertEqual( + expected, + actual, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty()))); + + return true; + } + + public virtual bool AssertEqualBase( + IColumnMappingBase expected, + IColumnMappingBase actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations) + { + Assert.Multiple( + () => Assert.Equal(expected.Column.Name, actual.Column.Name), + () => Assert.Equal(expected.Property.Name, actual.Property.Name), + () => Assert.Equal(expected.TypeMapping.StoreType, actual.TypeMapping.StoreType), + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + + return true; + } + + public virtual bool AssertEqual( + IColumnMappingBase expected, + IColumnMappingBase actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations) + { + Assert.Multiple( + () => AssertEqualBase(expected, actual, expectedAnnotations, actualAnnotations), + () => Assert.Contains(actual, actual.TableMapping.ColumnMappings)); + + return true; + } + + public virtual bool AssertEqual( + IColumnMapping expected, + IColumnMapping actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations) + { + Assert.Multiple( + () => AssertEqualBase(expected, actual, expectedAnnotations, actualAnnotations), + () => Assert.Contains(actual, actual.TableMapping.ColumnMappings)); + + return true; + } + public virtual bool AssertEqual( + IViewColumnMapping expected, + IViewColumnMapping actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations) + { + Assert.Multiple( + () => AssertEqualBase(expected, actual, expectedAnnotations, actualAnnotations), + () => Assert.Contains(actual, actual.ViewMapping.ColumnMappings)); + + return true; + } + + public virtual bool AssertEqual( + ISqlQueryColumnMapping expected, + ISqlQueryColumnMapping actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations) + { + Assert.Multiple( + () => AssertEqualBase(expected, actual, expectedAnnotations, actualAnnotations), + () => Assert.Contains(actual, actual.SqlQueryMapping.ColumnMappings)); + + return true; + } + + public virtual bool AssertEqual( + IFunctionColumnMapping expected, + IFunctionColumnMapping actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations) + { + Assert.Multiple( + () => AssertEqualBase(expected, actual, expectedAnnotations, actualAnnotations), + () => Assert.Contains(actual, actual.FunctionMapping.ColumnMappings)); + + return true; + } + + public virtual bool AssertEqual( + IStoredProcedureResultColumnMapping expected, + IStoredProcedureResultColumnMapping actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations) + { + Assert.Multiple( + () => AssertEqualBase(expected, actual, expectedAnnotations, actualAnnotations), + () => Assert.Contains(actual, actual.StoredProcedureMapping.ColumnMappings)); + + return true; + } + + public virtual bool AssertEqual( + IStoredProcedureParameterMapping expected, + IStoredProcedureParameterMapping actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations) + { + Assert.Multiple( + () => AssertEqualBase(expected, actual, expectedAnnotations, actualAnnotations), + () => Assert.Contains(actual, actual.StoredProcedureMapping.ParameterMappings)); + + return true; + } + + public virtual bool AssertEqual( + ITableIndex expected, + ITableIndex actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations) + { + Assert.Multiple( + () => Assert.Equal(expected.Name, actual.Name), + () => Assert.Contains(actual, actual.Table.Indexes), + () => Assert.Equal(expected.Columns.Select(c => c.Name), actual.Columns.Select(c => c.Name)), + () => Assert.Equal( + actual.MappedIndexes.Select(i => i.Properties.Select(p => p.Name)), + expected.MappedIndexes.Select(i => i.Properties.Select(p => p.Name))), + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + + return true; + } + + public virtual bool AssertEqual( + IForeignKeyConstraint expected, + IForeignKeyConstraint actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations) + { + Assert.Multiple( + () => Assert.Equal(expected.Name, actual.Name), + () => Assert.Equal(expected.OnDeleteAction, actual.OnDeleteAction), + () => Assert.Equal(expected.PrincipalUniqueConstraint.Name, actual.PrincipalUniqueConstraint.Name), + () => Assert.Equal(expected.PrincipalTable.SchemaQualifiedName, actual.PrincipalTable.SchemaQualifiedName), + () => Assert.Contains(actual, actual.Table.ForeignKeyConstraints), + () => Assert.Equal(expected.Columns.Select(c => c.Name), actual.Columns.Select(c => c.Name)), + () => Assert.Equal(expected.PrincipalColumns.Select(c => c.Name), actual.PrincipalColumns.Select(c => c.Name)), + () => Assert.Equal( + actual.MappedForeignKeys.Select(i => i.Properties.Select(p => p.Name)), + expected.MappedForeignKeys.Select(i => i.Properties.Select(p => p.Name))), + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + + return true; + } + + public virtual bool AssertEqual( + IUniqueConstraint expected, + IUniqueConstraint actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations) + { + Assert.Multiple( + () => Assert.Equal(expected.Name, actual.Name), + () => Assert.Equal(expected.GetIsPrimaryKey(), actual.GetIsPrimaryKey()), + () => Assert.Contains(actual, actual.Table.UniqueConstraints), + () => Assert.Equal(expected.Columns.Select(c => c.Name), actual.Columns.Select(c => c.Name)), + () => Assert.Equal( + actual.MappedKeys.Select(i => i.Properties.Select(p => p.Name)), + expected.MappedKeys.Select(i => i.Properties.Select(p => p.Name))), + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + + return true; + } + + public virtual bool AssertEqual( + ITrigger expected, + ITrigger actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations) + { + Assert.Multiple( + () => Assert.Equal(expected.ModelName, actual.ModelName), + () => Assert.Equal(expected.GetTableName(), actual.GetTableName()), + () => Assert.Equal(expected.GetTableSchema(), actual.GetTableSchema()), + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + + return true; + } +} diff --git a/test/EFCore.Relational.Specification.Tests/TestUtilities/RelationalTestHelpers.cs b/test/EFCore.Relational.Specification.Tests/TestUtilities/RelationalTestHelpers.cs index b71d3fc1033..5b53c7eb7e4 100644 --- a/test/EFCore.Relational.Specification.Tests/TestUtilities/RelationalTestHelpers.cs +++ b/test/EFCore.Relational.Specification.Tests/TestUtilities/RelationalTestHelpers.cs @@ -5,4 +5,5 @@ namespace Microsoft.EntityFrameworkCore.TestUtilities; public abstract class RelationalTestHelpers : TestHelpers { + public override ModelAsserter ModelAsserter => RelationalModelAsserter.Instance; } diff --git a/test/EFCore.Relational.Tests/Extensions/RelationalBuilderExtensionsTest.cs b/test/EFCore.Relational.Tests/Extensions/RelationalBuilderExtensionsTest.cs index 9119c45a2a1..930a26fa801 100644 --- a/test/EFCore.Relational.Tests/Extensions/RelationalBuilderExtensionsTest.cs +++ b/test/EFCore.Relational.Tests/Extensions/RelationalBuilderExtensionsTest.cs @@ -1187,7 +1187,7 @@ public void Can_access_comment() public void Can_create_dbFunction() { var modelBuilder = CreateConventionModelBuilder(); - var testMethod = typeof(TestDbFunctions).GetTypeInfo().GetDeclaredMethod(nameof(TestDbFunctions.MethodA)); + var testMethod = typeof(RelationalBuilderExtensionsTest).GetTypeInfo().GetDeclaredMethod(nameof(MethodA)); modelBuilder.HasDbFunction(testMethod); var dbFunc = modelBuilder.Model.FindDbFunction(testMethod) as DbFunction; @@ -1197,6 +1197,9 @@ public void Can_create_dbFunction() Assert.Null(dbFunc.Schema); } + public static int MethodA(string a, int b) + => throw new NotImplementedException(); + [ConditionalFact] public void Relational_entity_methods_dont_break_out_of_the_generics() { diff --git a/test/EFCore.Relational.Tests/Extensions/RelationalMetadataExtensionsTest.cs b/test/EFCore.Relational.Tests/Extensions/RelationalMetadataExtensionsTest.cs index 9243c84f9b3..8f7f9aa6197 100644 --- a/test/EFCore.Relational.Tests/Extensions/RelationalMetadataExtensionsTest.cs +++ b/test/EFCore.Relational.Tests/Extensions/RelationalMetadataExtensionsTest.cs @@ -406,7 +406,7 @@ public void Can_get_and_set_schema_name_on_model() [ConditionalFact] public void Can_get_and_set_dbfunction() { - var testMethod = typeof(TestDbFunctions).GetTypeInfo().GetDeclaredMethod(nameof(TestDbFunctions.MethodA)); + var testMethod = typeof(RelationalMetadataExtensionsTest).GetTypeInfo().GetDeclaredMethod(nameof(MethodA)); var modelBuilder = new ModelBuilder(); var model = modelBuilder.Model; @@ -425,6 +425,9 @@ public void Can_get_and_set_dbfunction() Assert.False(((IConventionDbFunction)dbFunc).IsInModel); } + public static int MethodA(string a, int b) + => throw new NotImplementedException(); + [ConditionalFact] public void Can_get_and_set_sequence() { diff --git a/test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs b/test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs index c5b569922bf..f69783efe91 100644 --- a/test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs +++ b/test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs @@ -3150,420 +3150,8 @@ protected virtual TestHelpers.TestModelBuilder CreateConventionModelBuilder() .Ignore(RelationalEventId.ForeignKeyTpcPrincipalWarning) .Ignore(RelationalEventId.AllIndexPropertiesNotToMappedToAnyTable))); - #region Asserters - public static void AssertEqual(IRelationalModel expectedModel, IRelationalModel actualModel) - { - ((RelationalModel)expectedModel).DefaultTables.Values.ZipAssert( - ((RelationalModel)actualModel).DefaultTables.Values, AssertEqual); - - expectedModel.Tables.ZipAssert(actualModel.Tables, AssertEqual); - expectedModel.Views.ZipAssert(actualModel.Views, AssertEqual); - expectedModel.Queries.ZipAssert(actualModel.Queries, AssertEqual); - expectedModel.Functions.ZipAssert(actualModel.Functions, AssertEqual); - expectedModel.StoredProcedures.ZipAssert(actualModel.StoredProcedures, AssertEqual); - - Assert.Equal(((RelationalModel)expectedModel).IsReadOnly, ((RelationalModel)actualModel).IsReadOnly); - Assert.Equal(expectedModel.GetAnnotations(), actualModel.GetAnnotations(), TestAnnotationComparer.Instance); - Assert.Equal(expectedModel.GetRuntimeAnnotations(), actualModel.GetRuntimeAnnotations(), TestAnnotationComparer.Instance); - } - - public static void AssertEqualBase(ITableBase expected, ITableBase actual) - { - Assert.Equal(expected.Name, actual.Name); - Assert.Equal(expected.Schema, actual.Schema); - Assert.Equal(expected.IsShared, actual.IsShared); - - foreach (IEntityType expectedEntityType in expected.EntityTypeMappings.Select(m => m.TypeBase)) - { - var actualEntityType = - (IEntityType)actual.EntityTypeMappings.Single(m => m.TypeBase.Name == expectedEntityType.Name).TypeBase; - Assert.Equal( - expected.GetRowInternalForeignKeys(expectedEntityType).Count(), - actual.GetRowInternalForeignKeys(actualEntityType).Count()); - Assert.Equal( - expected.GetReferencingRowInternalForeignKeys(expectedEntityType).Count(), - actual.GetReferencingRowInternalForeignKeys(actualEntityType).Count()); - } - - foreach (var expectedEntityType in expected.ComplexTypeMappings.Select(m => m.TypeBase)) - { - var actualEntityType = actual.ComplexTypeMappings.Single(m => m.TypeBase.Name == expectedEntityType.Name).TypeBase; - } - - Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), TestAnnotationComparer.Instance); - Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), TestAnnotationComparer.Instance); - } - - public static void AssertEqual(ITableBase expected, ITableBase actual) - { - AssertEqualBase(expected, actual); - - expected.Columns.ZipAssert(actual.Columns, AssertEqual); - expected.EntityTypeMappings.ZipAssert(actual.EntityTypeMappings, AssertEqual); - - Assert.Same(actual, ((RelationalModel)actual.Model).DefaultTables[actual.Name]); - } - - public static void AssertEqualBase(ITableMappingBase expected, ITableMappingBase actual) - { - Assert.Equal(expected.TypeBase.Name, actual.TypeBase.Name); - Assert.Equal(expected.Table.SchemaQualifiedName, actual.Table.SchemaQualifiedName); - Assert.Equal(expected.IncludesDerivedTypes, actual.IncludesDerivedTypes); - Assert.Equal(expected.IsSharedTablePrincipal, actual.IsSharedTablePrincipal); - Assert.Equal(expected.IsSplitEntityTypePrincipal, actual.IsSplitEntityTypePrincipal); - - Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), TestAnnotationComparer.Instance); - Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), TestAnnotationComparer.Instance); - } - - public static void AssertEqual(ITableMappingBase expected, ITableMappingBase actual) - { - AssertEqualBase(expected, actual); - - expected.ColumnMappings.ZipAssert(actual.ColumnMappings, AssertEqual); - } - - public static void AssertEqualBase(IColumnBase expected, IColumnBase actual) - { - Assert.Equal(expected.Name, actual.Name); - Assert.Equal(expected.IsNullable, actual.IsNullable); - Assert.Equal(expected.ProviderClrType, actual.ProviderClrType); - Assert.Equal(expected.StoreType, actual.StoreType); - Assert.Equal(expected.StoreTypeMapping.StoreType, actual.StoreTypeMapping.StoreType); - - Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), TestAnnotationComparer.Instance); - Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), TestAnnotationComparer.Instance); - } - - public static void AssertEqual(IColumnBase expected, IColumnBase actual) - { - AssertEqualBase(expected, actual); - - expected.PropertyMappings.ZipAssert(actual.PropertyMappings, AssertEqual); - - Assert.Same(actual, actual.Table.FindColumn(actual.Name)); - } - - public static void AssertEqualBase(IColumnMappingBase expected, IColumnMappingBase actual) - { - Assert.Equal(expected.Column.Name, actual.Column.Name); - Assert.Equal(expected.Property.Name, actual.Property.Name); - Assert.Equal(expected.TypeMapping.StoreType, actual.TypeMapping.StoreType); - - Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), TestAnnotationComparer.Instance); - Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), TestAnnotationComparer.Instance); - } - - public static void AssertEqual(IColumnMappingBase expected, IColumnMappingBase actual) - { - AssertEqualBase(expected, actual); - - Assert.Contains(actual, actual.TableMapping.ColumnMappings); - } - - public static void AssertEqual(ITable expected, ITable actual) - { - AssertEqualBase(expected, actual); - - expected.Columns.ZipAssert(actual.Columns, AssertEqual); - expected.Indexes.ZipAssert(actual.Indexes, AssertEqual); - expected.ForeignKeyConstraints.ZipAssert(actual.ForeignKeyConstraints, AssertEqual); - expected.ReferencingForeignKeyConstraints.ZipAssert(actual.ReferencingForeignKeyConstraints, AssertEqual); - expected.UniqueConstraints.ZipAssert(actual.UniqueConstraints, AssertEqual); - expected.Triggers.ZipAssert(actual.Triggers, AssertEqual); - - Assert.Same(actual, actual.Model.FindTable(actual.Name, actual.Schema)); - expected.EntityTypeMappings.ZipAssert(actual.EntityTypeMappings, AssertEqual); - } - - public static void AssertEqual(ITableMapping expected, ITableMapping actual) - { - AssertEqualBase(expected, actual); - - AssertEqual(expected.DeleteStoredProcedureMapping, actual.DeleteStoredProcedureMapping); - AssertEqual(expected.InsertStoredProcedureMapping, actual.InsertStoredProcedureMapping); - AssertEqual(expected.UpdateStoredProcedureMapping, actual.UpdateStoredProcedureMapping); - - expected.ColumnMappings.ZipAssert(actual.ColumnMappings, AssertEqual); - } - - public static void AssertEqual(IColumn expected, IColumn actual) - { - AssertEqualBase(expected, actual); - - expected.PropertyMappings.ZipAssert(actual.PropertyMappings, AssertEqual); - - Assert.Same(actual, actual.Table.FindColumn(actual.Name)); - } - - public static void AssertEqual(IColumnMapping expected, IColumnMapping actual) - { - AssertEqualBase(expected, actual); - - Assert.Contains(actual, actual.TableMapping.ColumnMappings); - } - - public static void AssertEqual(ITableIndex expected, ITableIndex actual) - { - Assert.Equal(expected.Columns.Select(c => c.Name), actual.Columns.Select(c => c.Name)); - Assert.Equal(expected.Name, actual.Name); - Assert.Contains(actual, actual.Table.Indexes); - Assert.Equal( - actual.MappedIndexes.Select(i => i.Properties.Select(p => p.Name)), - expected.MappedIndexes.Select(i => i.Properties.Select(p => p.Name))); - - Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), TestAnnotationComparer.Instance); - Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), TestAnnotationComparer.Instance); - } - - public static void AssertEqual(IForeignKeyConstraint expected, IForeignKeyConstraint actual) - { - Assert.Equal(expected.Columns.Select(c => c.Name), actual.Columns.Select(c => c.Name)); - Assert.Equal(expected.PrincipalColumns.Select(c => c.Name), actual.PrincipalColumns.Select(c => c.Name)); - Assert.Equal(expected.Name, actual.Name); - Assert.Equal(expected.OnDeleteAction, actual.OnDeleteAction); - Assert.Equal(expected.PrincipalUniqueConstraint.Name, actual.PrincipalUniqueConstraint.Name); - Assert.Equal(expected.PrincipalTable.SchemaQualifiedName, actual.PrincipalTable.SchemaQualifiedName); - Assert.Contains(actual, actual.Table.ForeignKeyConstraints); - Assert.Equal( - actual.MappedForeignKeys.Select(i => i.Properties.Select(p => p.Name)), - expected.MappedForeignKeys.Select(i => i.Properties.Select(p => p.Name))); - - Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), TestAnnotationComparer.Instance); - Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), TestAnnotationComparer.Instance); - } - - public static void AssertEqual(IUniqueConstraint expected, IUniqueConstraint actual) - { - Assert.Equal(expected.Columns.Select(c => c.Name), actual.Columns.Select(c => c.Name)); - Assert.Equal(expected.Name, actual.Name); - Assert.Equal(expected.GetIsPrimaryKey(), actual.GetIsPrimaryKey()); - Assert.Contains(actual, actual.Table.UniqueConstraints); - Assert.Equal( - actual.MappedKeys.Select(i => i.Properties.Select(p => p.Name)), - expected.MappedKeys.Select(i => i.Properties.Select(p => p.Name))); - - Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), TestAnnotationComparer.Instance); - Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), TestAnnotationComparer.Instance); - } - - public static void AssertEqual(ITrigger expected, ITrigger actual) - { - Assert.Equal(expected.ModelName, actual.ModelName); - Assert.Equal(expected.GetTableName(), actual.GetTableName()); - Assert.Equal(expected.GetTableSchema(), actual.GetTableSchema()); - - Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), TestAnnotationComparer.Instance); - Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), TestAnnotationComparer.Instance); - } - - public static void AssertEqual(IView expected, IView actual) - { - AssertEqualBase(expected, actual); - - expected.Columns.ZipAssert(actual.Columns, AssertEqual); - - Assert.Same(actual, actual.Model.FindView(actual.Name, actual.Schema)); - expected.EntityTypeMappings.ZipAssert(actual.EntityTypeMappings, AssertEqual); - } - - public static void AssertEqual(IViewMapping expected, IViewMapping actual) - { - AssertEqualBase(expected, actual); - - expected.ColumnMappings.ZipAssert(actual.ColumnMappings, AssertEqual); - } - - public static void AssertEqual(IViewColumn expected, IViewColumn actual) - { - AssertEqualBase(expected, actual); - - expected.PropertyMappings.ZipAssert(actual.PropertyMappings, AssertEqual); - - Assert.Same(actual, actual.View.FindColumn(actual.Name)); - } - - public static void AssertEqual(IViewColumnMapping expected, IViewColumnMapping actual) - { - AssertEqualBase(expected, actual); - - Assert.Contains(actual, actual.ViewMapping.ColumnMappings); - } - - public static void AssertEqual(ISqlQuery expected, ISqlQuery actual) - { - AssertEqualBase(expected, actual); - - expected.Columns.ZipAssert(actual.Columns, AssertEqual); - Assert.Equal(expected.Sql, actual.Sql); - - Assert.Same(actual, actual.Model.FindQuery(actual.Name)); - expected.EntityTypeMappings.ZipAssert(actual.EntityTypeMappings, AssertEqual); - } - - public static void AssertEqual(ISqlQueryMapping expected, ISqlQueryMapping actual) - { - AssertEqualBase(expected, actual); - - Assert.Equal(expected.IsDefaultSqlQueryMapping, actual.IsDefaultSqlQueryMapping); - - expected.ColumnMappings.ZipAssert(actual.ColumnMappings, AssertEqual); - } - - public static void AssertEqual(ISqlQueryColumn expected, ISqlQueryColumn actual) - { - AssertEqualBase(expected, actual); - - expected.PropertyMappings.ZipAssert(actual.PropertyMappings, AssertEqual); - - Assert.Same(actual, actual.SqlQuery.FindColumn(actual.Name)); - } - - public static void AssertEqual(ISqlQueryColumnMapping expected, ISqlQueryColumnMapping actual) - { - AssertEqualBase(expected, actual); - - Assert.Contains(actual, actual.SqlQueryMapping.ColumnMappings); - } - - public static void AssertEqual(IStoreFunction expected, IStoreFunction actual) - { - AssertEqualBase(expected, actual); - - expected.Parameters.ZipAssert(actual.Parameters, AssertEqual); - expected.Columns.ZipAssert(actual.Columns, AssertEqual); - Assert.Equal(expected.ReturnType, actual.ReturnType); - Assert.Equal(expected.IsBuiltIn, actual.IsBuiltIn); - - Assert.Same( - actual, actual.Model.FindFunction(actual.Name, actual.Schema, actual.Parameters.Select(p => p.StoreType).ToArray())); - Assert.Equal( - actual.DbFunctions.Select(p => p.ModelName), - expected.DbFunctions.Select(p => p.ModelName)); - expected.EntityTypeMappings.ZipAssert(actual.EntityTypeMappings, AssertEqual); - } - - public static void AssertEqual(IFunctionMapping expected, IFunctionMapping actual) - { - AssertEqualBase(expected, actual); - - expected.ColumnMappings.ZipAssert(actual.ColumnMappings, AssertEqual); - - Assert.Equal(expected.IsDefaultFunctionMapping, actual.IsDefaultFunctionMapping); - Assert.Contains(expected.DbFunction.Name, actual.DbFunction.Name); - - Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), TestAnnotationComparer.Instance); - Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), TestAnnotationComparer.Instance); - } - - public static void AssertEqual(IFunctionColumn expected, IFunctionColumn actual) - { - AssertEqualBase(expected, actual); - - expected.PropertyMappings.ZipAssert(actual.PropertyMappings, AssertEqual); - - Assert.Same(actual, actual.Function.FindColumn(actual.Name)); - } - - public static void AssertEqual(IFunctionColumnMapping expected, IFunctionColumnMapping actual) - { - AssertEqualBase(expected, actual); - - Assert.Contains(actual, actual.FunctionMapping.ColumnMappings); - } - - public static void AssertEqual(IStoreFunctionParameter expected, IStoreFunctionParameter actual) - { - Assert.Equal(expected.Name, actual.Name); - Assert.Equal(expected.StoreType, actual.StoreType); - Assert.Contains(actual, actual.Function.Parameters); - Assert.Equal(expected.DbFunctionParameters.Select(p => p.Name), actual.DbFunctionParameters.Select(p => p.Name)); - - Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), TestAnnotationComparer.Instance); - Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), TestAnnotationComparer.Instance); - } - - public static void AssertEqual(IStoreStoredProcedure expected, IStoreStoredProcedure actual) - { - AssertEqualBase(expected, actual); - - expected.Parameters.ZipAssert(actual.Parameters, AssertEqual); - expected.ResultColumns.ZipAssert(actual.ResultColumns, AssertEqual); - if (expected.ReturnValue == null) - { - Assert.Null(actual.ReturnValue); - return; - } - - AssertEqualBase(expected.ReturnValue, actual.ReturnValue); - Assert.Same(actual, actual.ReturnValue.StoredProcedure); - expected.ReturnValue.PropertyMappings.ZipAssert(actual.ReturnValue.PropertyMappings, AssertEqual); - - Assert.Same(actual, actual.Model.FindStoredProcedure(actual.Name, actual.Schema)); - Assert.Equal( - actual.StoredProcedures.Select(p => p.Name), - expected.StoredProcedures.Select(p => p.Name)); - expected.EntityTypeMappings.ZipAssert(actual.EntityTypeMappings, AssertEqual); - } - - public static void AssertEqual(IStoredProcedureMapping expected, IStoredProcedureMapping actual) - { - if (expected == null) - { - Assert.Null(actual); - return; - } - - AssertEqualBase(expected, actual); - - expected.ResultColumnMappings.ZipAssert(actual.ResultColumnMappings, AssertEqual); - expected.ParameterMappings.ZipAssert(actual.ParameterMappings, AssertEqual); - Assert.Equal(expected.StoredProcedure.GetSchemaQualifiedName(), actual.StoredProcedure.GetSchemaQualifiedName()); - Assert.Equal(expected.StoreStoredProcedure.SchemaQualifiedName, actual.StoreStoredProcedure.SchemaQualifiedName); - - Assert.Contains(expected.TableMapping?.Table.SchemaQualifiedName, actual.TableMapping?.Table.SchemaQualifiedName); - - Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), TestAnnotationComparer.Instance); - Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), TestAnnotationComparer.Instance); - } - - public static void AssertEqual(IStoreStoredProcedureResultColumn expected, IStoreStoredProcedureResultColumn actual) - { - AssertEqualBase(expected, actual); - - expected.PropertyMappings.ZipAssert(actual.PropertyMappings, AssertEqual); - Assert.Equal(expected.Position, actual.Position); - - Assert.Same(actual, actual.StoredProcedure.FindResultColumn(actual.Name)); - } - - public static void AssertEqual(IStoredProcedureResultColumnMapping expected, IStoredProcedureResultColumnMapping actual) - { - AssertEqualBase(expected, actual); - - Assert.Contains(actual, actual.StoredProcedureMapping.ResultColumnMappings); - } - - public static void AssertEqual(IStoreStoredProcedureParameter expected, IStoreStoredProcedureParameter actual) - { - AssertEqualBase(expected, actual); - - expected.PropertyMappings.ZipAssert(actual.PropertyMappings, AssertEqual); - Assert.Equal(expected.Direction, actual.Direction); - Assert.Equal(expected.Position, actual.Position); - - Assert.Same(actual, actual.StoredProcedure.FindParameter(actual.Name)); - } - - public static void AssertEqual(IStoredProcedureParameterMapping expected, IStoredProcedureParameterMapping actual) - { - AssertEqualBase(expected, actual); - - Assert.Contains(actual, actual.StoredProcedureMapping.ParameterMappings); - } - - #endregion + => RelationalModelAsserter.Instance.AssertEqual(expectedModel, actualModel); public enum Mapping { diff --git a/test/EFCore.Relational.Tests/TestUtilities/FakeDatabaseModelFactory.cs b/test/EFCore.Relational.Tests/TestUtilities/FakeDatabaseModelFactory.cs index 74f7a668e8c..7ba4d36009e 100644 --- a/test/EFCore.Relational.Tests/TestUtilities/FakeDatabaseModelFactory.cs +++ b/test/EFCore.Relational.Tests/TestUtilities/FakeDatabaseModelFactory.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.EntityFrameworkCore.Scaffolding.Metadata; diff --git a/test/EFCore.Relational.Tests/TestUtilities/FakeRelationalTestHelpers.cs b/test/EFCore.Relational.Tests/TestUtilities/FakeRelationalTestHelpers.cs index ebd475025d6..8f1b2ec34a2 100644 --- a/test/EFCore.Relational.Tests/TestUtilities/FakeRelationalTestHelpers.cs +++ b/test/EFCore.Relational.Tests/TestUtilities/FakeRelationalTestHelpers.cs @@ -24,4 +24,6 @@ public override DbContextOptionsBuilder UseProviderOptions(DbContextOptionsBuild => optionsBuilder.UseFakeRelational(); public override LoggingDefinitions LoggingDefinitions { get; } = new TestRelationalLoggingDefinitions(); + + public override ModelAsserter ModelAsserter => RelationalModelAsserter.Instance; } diff --git a/test/EFCore.Relational.Tests/TestUtilities/TestDbFunctions.cs b/test/EFCore.Relational.Tests/TestUtilities/TestDbFunctions.cs deleted file mode 100644 index a71cc446077..00000000000 --- a/test/EFCore.Relational.Tests/TestUtilities/TestDbFunctions.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace Microsoft.EntityFrameworkCore.TestUtilities; - -public static class TestDbFunctions -{ - public static int MethodA(string a, int b) - => throw new NotImplementedException(); -} diff --git a/test/EFCore.Relational.Tests/TestUtilities/TestModificationCommandBatch.cs b/test/EFCore.Relational.Tests/TestUtilities/TestModificationCommandBatch.cs index 0dca9e838c6..a8957ff62f6 100644 --- a/test/EFCore.Relational.Tests/TestUtilities/TestModificationCommandBatch.cs +++ b/test/EFCore.Relational.Tests/TestUtilities/TestModificationCommandBatch.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. namespace Microsoft.EntityFrameworkCore.TestUtilities; diff --git a/test/EFCore.Relational.Tests/TestUtilities/TestModificationCommandBatchFactory.cs b/test/EFCore.Relational.Tests/TestUtilities/TestModificationCommandBatchFactory.cs index 3e1bfe76ccb..b3e62c344c8 100644 --- a/test/EFCore.Relational.Tests/TestUtilities/TestModificationCommandBatchFactory.cs +++ b/test/EFCore.Relational.Tests/TestUtilities/TestModificationCommandBatchFactory.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.EntityFrameworkCore.TestUtilities.FakeProvider; diff --git a/test/EFCore.Relational.Tests/TestUtilities/TestProviderCodeGenerator.cs b/test/EFCore.Relational.Tests/TestUtilities/TestProviderCodeGenerator.cs index 2ecb98f6100..0be490f9c04 100644 --- a/test/EFCore.Relational.Tests/TestUtilities/TestProviderCodeGenerator.cs +++ b/test/EFCore.Relational.Tests/TestUtilities/TestProviderCodeGenerator.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. namespace Microsoft.EntityFrameworkCore.TestUtilities; diff --git a/test/EFCore.Relational.Tests/TestUtilities/TestRelationalConventionSetBuilder.cs b/test/EFCore.Relational.Tests/TestUtilities/TestRelationalConventionSetBuilder.cs index 99df9f0fd93..496502c45c6 100644 --- a/test/EFCore.Relational.Tests/TestUtilities/TestRelationalConventionSetBuilder.cs +++ b/test/EFCore.Relational.Tests/TestUtilities/TestRelationalConventionSetBuilder.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. namespace Microsoft.EntityFrameworkCore.TestUtilities; diff --git a/test/EFCore.Specification.Tests/EFCore.Specification.Tests.csproj b/test/EFCore.Specification.Tests/EFCore.Specification.Tests.csproj index 82ce956b506..37019a1aa28 100644 --- a/test/EFCore.Specification.Tests/EFCore.Specification.Tests.csproj +++ b/test/EFCore.Specification.Tests/EFCore.Specification.Tests.csproj @@ -64,4 +64,23 @@ + + + TextTemplatingFileGenerator + GiantModel.cs + + + + + + + + + + True + True + GiantModel.tt + + + diff --git a/test/EFCore.Tests/ModelBuilding/GiantModel.cs b/test/EFCore.Specification.Tests/ModelBuilding/GiantModel.cs similarity index 99% rename from test/EFCore.Tests/ModelBuilding/GiantModel.cs rename to test/EFCore.Specification.Tests/ModelBuilding/GiantModel.cs index 2784a30ee9f..32db7483401 100644 --- a/test/EFCore.Tests/ModelBuilding/GiantModel.cs +++ b/test/EFCore.Specification.Tests/ModelBuilding/GiantModel.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // - namespace Microsoft.EntityFrameworkCore.ModelBuilding; public static class GiantModel diff --git a/test/EFCore.Tests/ModelBuilding/GiantModel.tt b/test/EFCore.Specification.Tests/ModelBuilding/GiantModel.tt similarity index 100% rename from test/EFCore.Tests/ModelBuilding/GiantModel.tt rename to test/EFCore.Specification.Tests/ModelBuilding/GiantModel.tt diff --git a/test/EFCore.Tests/ModelBuilding/ComplexTypeTestBase.cs b/test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.ComplexType.cs similarity index 98% rename from test/EFCore.Tests/ModelBuilding/ComplexTypeTestBase.cs rename to test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.ComplexType.cs index f67d32be50e..3232e70ead3 100644 --- a/test/EFCore.Tests/ModelBuilding/ComplexTypeTestBase.cs +++ b/test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.ComplexType.cs @@ -527,22 +527,22 @@ public virtual void Properties_can_have_provider_type_set() var up = complexType.FindProperty("Up"); Assert.Null(up.GetProviderClrType()); - Assert.IsType>(up.GetValueComparer()); + Assert.True(up.GetValueComparer().IsDefault()); var down = complexType.FindProperty("Down"); Assert.Same(typeof(byte[]), down.GetProviderClrType()); - Assert.IsType>(down.GetValueComparer()); + Assert.True(down.GetValueComparer().IsDefault()); Assert.IsType>(down.GetProviderValueComparer()); var charm = complexType.FindProperty("Charm"); Assert.Same(typeof(long), charm.GetProviderClrType()); Assert.IsType>(charm.GetValueComparer()); - Assert.IsType>(charm.GetProviderValueComparer()); + Assert.True(charm.GetProviderValueComparer().IsDefault()); var strange = complexType.FindProperty("Strange"); Assert.Null(strange.GetProviderClrType()); - Assert.IsType>(strange.GetValueComparer()); - Assert.IsType>(strange.GetProviderValueComparer()); + Assert.True(strange.GetValueComparer().IsDefault()); + Assert.True(strange.GetProviderValueComparer().IsDefault()); var top = complexType.FindProperty("Top"); Assert.Same(typeof(string), top.GetProviderClrType()); @@ -608,12 +608,12 @@ public virtual void Properties_can_have_non_generic_value_converter_set() var down = complexType.FindProperty("Down"); Assert.Same(stringConverter, down.GetValueConverter()); - Assert.IsType>(down.GetValueComparer()); + Assert.True(down.GetValueComparer().IsDefault()); Assert.IsType>(down.GetProviderValueComparer()); var charm = complexType.FindProperty("Charm"); Assert.Same(intConverter, charm.GetValueConverter()); - Assert.IsType>(charm.GetValueComparer()); + Assert.True(charm.GetValueComparer().IsDefault()); Assert.IsType>(charm.GetProviderValueComparer()); Assert.Null(complexType.FindProperty("Strange").GetValueConverter()); @@ -657,12 +657,12 @@ public virtual void Properties_can_have_custom_type_value_converter_type_set() var charm = complexType.FindProperty("Charm"); Assert.IsType>(charm.GetValueConverter()); Assert.IsType>(charm.GetValueComparer()); - Assert.IsType>(charm.GetProviderValueComparer()); + Assert.True(charm.GetProviderValueComparer().IsDefault()); var strange = complexType.FindProperty("Strange"); Assert.Null(strange.GetValueConverter()); - Assert.IsType>(strange.GetValueComparer()); - Assert.IsType>(strange.GetProviderValueComparer()); + Assert.True(strange.GetValueComparer().IsDefault()); + Assert.True(strange.GetProviderValueComparer().IsDefault()); } private class UTF8StringToBytesConverter : StringToBytesConverter @@ -707,18 +707,18 @@ public virtual void Properties_can_have_value_converter_set_inline() var up = complexType.FindProperty("Up"); Assert.Null(up.GetProviderClrType()); Assert.Null(up.GetValueConverter()); - Assert.IsType>(up.GetValueComparer()); - Assert.IsType>(up.GetProviderValueComparer()); + Assert.True(up.GetValueComparer().IsDefault()); + Assert.True(up.GetProviderValueComparer().IsDefault()); var down = complexType.FindProperty("Down"); Assert.IsType>(down.GetValueConverter()); - Assert.IsType>(down.GetValueComparer()); - Assert.IsType>(down.GetProviderValueComparer()); + Assert.True(down.GetValueComparer().IsDefault()); + Assert.True(down.GetProviderValueComparer().IsDefault()); var charm = complexType.FindProperty("Charm"); Assert.IsType>(charm.GetValueConverter()); Assert.IsType>(charm.GetValueComparer()); - Assert.IsType>(charm.GetProviderValueComparer()); + Assert.True(charm.GetProviderValueComparer().IsDefault()); var strange = complexType.FindProperty("Strange"); Assert.IsType>(strange.GetValueConverter()); @@ -755,18 +755,18 @@ public virtual void Properties_can_have_value_converter_set() var up = complexType.FindProperty("Up"); Assert.Null(up.GetProviderClrType()); Assert.Null(up.GetValueConverter()); - Assert.IsType>(up.GetValueComparer()); - Assert.IsType>(up.GetProviderValueComparer()); + Assert.True(up.GetValueComparer().IsDefault()); + Assert.True(up.GetProviderValueComparer().IsDefault()); var down = complexType.FindProperty("Down"); Assert.IsType>(down.GetValueConverter()); - Assert.IsType>(down.GetValueComparer()); - Assert.IsType>(down.GetProviderValueComparer()); + Assert.True(down.GetValueComparer().IsDefault()); + Assert.True(down.GetProviderValueComparer().IsDefault()); var charm = complexType.FindProperty("Charm"); Assert.IsType>(charm.GetValueConverter()); Assert.IsType>(charm.GetValueComparer()); - Assert.IsType>(charm.GetProviderValueComparer()); + Assert.True(charm.GetProviderValueComparer().IsDefault()); var strange = complexType.FindProperty("Strange"); Assert.IsType>(strange.GetValueConverter()); diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs b/test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.Generic.cs similarity index 93% rename from test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs rename to test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.Generic.cs index e4b82d348ce..fc0b74806d0 100644 --- a/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs +++ b/test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.Generic.cs @@ -1,187 +1,17 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#nullable enable - -using Microsoft.EntityFrameworkCore.Metadata.Internal; - // ReSharper disable InconsistentNaming namespace Microsoft.EntityFrameworkCore.ModelBuilding; -public class ModelBuilderGenericTest : ModelBuilderTest -{ - [ConditionalFact] - public void Can_create_a_model_builder_with_given_conventions_only() - { - var convention = new TestConvention(); - var conventions = new ConventionSet(); - conventions.EntityTypeAddedConventions.Add(convention); - - var modelBuilder = new ModelBuilder(conventions); - - modelBuilder.Entity(); - - Assert.True(convention.Applied); - Assert.NotNull(modelBuilder.Model.FindEntityType(typeof(Random))); - } - - private class TestConvention : IEntityTypeAddedConvention - { - public bool Applied { get; private set; } - - public void ProcessEntityTypeAdded( - IConventionEntityTypeBuilder entityTypeBuilder, - IConventionContext context) - => Applied = true; - } - - [ConditionalFact] - public void Can_discover_large_models_through_navigations() - { - var modelBuilder = InMemoryTestHelpers.Instance.CreateConventionBuilder(); - - modelBuilder.Entity(); - - Assert.Equal(2000, modelBuilder.Model.GetEntityTypes().Count()); - } - - public class GenericNonRelationship : NonRelationshipTestBase - { - public GenericNonRelationship(ModelBuilderFixtureBase fixture) - : base(fixture) - { - } - - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new GenericTestModelBuilder(testHelpers, configure); - - [ConditionalFact] - public virtual void Changing_propertyInfo_updates_Property() - { - var modelBuilder = CreateModelBuilder(); - - modelBuilder.Entity().Property(e => ((IReplaceable)e).Property); - - modelBuilder.FinalizeModel(); - - var property = modelBuilder.Model.FindEntityType(typeof(DoubleProperty))!.GetProperty("Property"); - Assert.EndsWith(typeof(IReplaceable).Name + "." + nameof(IReplaceable.Property), property.GetIdentifyingMemberInfo()!.Name); - } - } - - public class GenericComplexType : ComplexTypeTestBase - { - public GenericComplexType(ModelBuilderFixtureBase fixture) - : base(fixture) - { - } - - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new GenericTestModelBuilder(testHelpers, configure); - - [ConditionalFact] - public virtual void Changing_propertyInfo_updates_Property() - { - var modelBuilder = CreateModelBuilder(); - - modelBuilder - .Ignore() - .Entity().ComplexProperty(e => e.DoubleProperty).Property(e => ((IReplaceable?)e)!.Property); - - modelBuilder.FinalizeModel(); - - var property = modelBuilder.Model.FindEntityType(typeof(ComplexProperties))!.FindComplexProperty(nameof(DoubleProperty))! - .ComplexType.FindProperty("Property")!; - Assert.EndsWith(typeof(IReplaceable).Name + "." + nameof(IReplaceable.Property), property.GetIdentifyingMemberInfo()!.Name); - } - } - - public class GenericInheritance : InheritanceTestBase - { - public GenericInheritance(ModelBuilderFixtureBase fixture) - : base(fixture) - { - } - - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new GenericTestModelBuilder(testHelpers, configure); - } - - public class GenericOwnedTypes: OwnedTypesTestBase - { - public GenericOwnedTypes(ModelBuilderFixtureBase fixture) - : base(fixture) - { - } - - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new GenericTestModelBuilder(testHelpers, configure); - } - - public class GenericOneToMany : OneToManyTestBase - { - public GenericOneToMany(ModelBuilderFixtureBase fixture) - : base(fixture) - { - } - - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new GenericTestModelBuilder(testHelpers, configure); - } - - public class GenericManyToOne : ManyToOneTestBase - { - public GenericManyToOne(ModelBuilderFixtureBase fixture) - : base(fixture) - { - } - - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new GenericTestModelBuilder(testHelpers, configure); - } - - public class GenericManyToMany : ManyToManyTestBase - { - public GenericManyToMany(ModelBuilderFixtureBase fixture) - : base(fixture) - { - } - - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new GenericTestModelBuilder(testHelpers, configure); - } - - public class GenericOneToOne : OneToOneTestBase - { - public GenericOneToOne(ModelBuilderFixtureBase fixture) - : base(fixture) - { - } - - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new GenericTestModelBuilder(testHelpers, configure); - } +#nullable enable +public abstract partial class ModelBuilderTest +{ public class GenericTestModelBuilder : TestModelBuilder { - public GenericTestModelBuilder(TestHelpers testHelpers, Action? configure) - : base(testHelpers, configure) + public GenericTestModelBuilder(ModelBuilderFixtureBase fixture, Action? configure) + : base(fixture, configure) { } diff --git a/test/EFCore.Tests/ModelBuilding/InheritanceTestBase.cs b/test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.Inheritance.cs similarity index 94% rename from test/EFCore.Tests/ModelBuilding/InheritanceTestBase.cs rename to test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.Inheritance.cs index 70ad44cf5ee..84cab876a75 100644 --- a/test/EFCore.Tests/ModelBuilding/InheritanceTestBase.cs +++ b/test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.Inheritance.cs @@ -148,33 +148,55 @@ public virtual void Can_set_and_remove_base_type() Assert.Same(typeof(Ingredient), pickle.BaseType.ClrType); var actualProperties = pickle.GetProperties(); - Fixture.AssertEqual( + Fixture.TestHelpers.ModelAsserter.AssertEqual( initialProperties.Where(p => p.Name != "Discriminator"), actualProperties.Where(p => p.Name != "Discriminator")); + Assert.Equal(initialKeys, pickle.GetKeys(), + (expected, actual) => + { + Fixture.TestHelpers.ModelAsserter.AssertEqual( + expected.Properties, + actual.Properties); - Fixture.AssertEqual(initialKeys, pickle.GetKeys()); - Fixture.AssertEqual(initialIndexes, pickle.GetIndexes()); - Fixture.AssertEqual(initialForeignKeys, pickle.GetForeignKeys()); - Fixture.AssertEqual(initialReferencingForeignKeys, pickle.GetReferencingForeignKeys()); + return true; + }); + Fixture.TestHelpers.ModelAsserter.AssertEqual( + initialIndexes.Single().Properties, + pickle.GetIndexes().Single().Properties); + Fixture.TestHelpers.ModelAsserter.AssertEqual( + initialForeignKeys.Single().Properties, + pickle.GetForeignKeys().Single().Properties); + Fixture.TestHelpers.ModelAsserter.AssertEqual(initialReferencingForeignKeys, pickle.GetReferencingForeignKeys()); pickleBuilder.HasBaseType(null); Assert.Null(pickle.BaseType); actualProperties = pickle.GetProperties(); - Fixture.AssertEqual(initialProperties, actualProperties); - Fixture.AssertEqual(initialKeys, pickle.GetKeys()); - Fixture.AssertEqual(initialIndexes, pickle.GetIndexes()); - Fixture.AssertEqual(initialForeignKeys, pickle.GetForeignKeys()); - Fixture.AssertEqual(initialReferencingForeignKeys, pickle.GetReferencingForeignKeys()); + Fixture.TestHelpers.ModelAsserter.AssertEqual(initialProperties, actualProperties); + Fixture.TestHelpers.ModelAsserter.AssertEqual(initialKeys, pickle.GetKeys()); + Fixture.TestHelpers.ModelAsserter.AssertEqual(initialIndexes, pickle.GetIndexes()); + Fixture.TestHelpers.ModelAsserter.AssertEqual(initialForeignKeys, pickle.GetForeignKeys()); + Fixture.TestHelpers.ModelAsserter.AssertEqual(initialReferencingForeignKeys, pickle.GetReferencingForeignKeys()); actualProperties = ingredient.GetProperties(); - Fixture.AssertEqual( + Fixture.TestHelpers.ModelAsserter.AssertEqual( initialProperties.Where(p => p.Name != "Discriminator"), actualProperties.Where(p => p.Name != "Discriminator")); + Assert.Equal(initialKeys, ingredient.GetKeys(), + (expected, actual) => + { + Fixture.TestHelpers.ModelAsserter.AssertEqual( + expected.Properties, + actual.Properties); - Fixture.AssertEqual(initialKeys, ingredient.GetKeys()); - Fixture.AssertEqual(initialIndexes, ingredient.GetIndexes()); - Assert.Equal(initialForeignKeys.Count(), ingredient.GetForeignKeys().Count()); + return true; + }); + Fixture.TestHelpers.ModelAsserter.AssertEqual( + initialIndexes.Single().Properties, + ingredient.GetIndexes().Single().Properties); + Fixture.TestHelpers.ModelAsserter.AssertEqual( + initialForeignKeys.Single().Properties, + ingredient.GetForeignKeys().Single().Properties); Assert.Equal(initialReferencingForeignKeys.Count(), ingredient.GetReferencingForeignKeys().Count()); } @@ -606,10 +628,10 @@ public virtual void Index_removed_when_covered_by_an_inherited_foreign_key() Assert.Single(dependentEntityType.GetIndexes()); Assert.False(dependentEntityType.FindIndex(fk.Properties).IsUnique); - Fixture.AssertEqual(initialProperties, derivedDependentEntityType.GetProperties()); - Fixture.AssertEqual(initialKeys, derivedDependentEntityType.GetKeys()); - Fixture.AssertEqual(initialIndexes, derivedDependentEntityType.GetIndexes()); - Fixture.AssertEqual(initialForeignKeys, derivedDependentEntityType.GetForeignKeys()); + Fixture.TestHelpers.ModelAsserter.AssertEqual(initialProperties, derivedDependentEntityType.GetProperties()); + Fixture.TestHelpers.ModelAsserter.AssertEqual(initialKeys, derivedDependentEntityType.GetKeys()); + Fixture.TestHelpers.ModelAsserter.AssertEqual(initialIndexes, derivedDependentEntityType.GetIndexes()); + Fixture.TestHelpers.ModelAsserter.AssertEqual(initialForeignKeys, derivedDependentEntityType.GetForeignKeys()); principalEntityBuilder.HasOne().WithOne() .HasPrincipalKey( @@ -679,13 +701,6 @@ public virtual void Index_removed_when_covered_by_an_inherited_index() derivedDependentEntityBuilder.HasBaseType(); - modelBuilder.FinalizeModel(); - - var indexRemoveMessage = - CoreResources.LogRedundantIndexRemoved(new TestLogger()).GenerateMessage( - "{'CustomerId'}", nameof(Order), "{'CustomerId', 'AnotherCustomerId'}"); - Assert.Equal(1, modelBuilder.ModelLoggerFactory.Log.Count(l => l.Message == indexRemoveMessage)); - var baseFK = dependentEntityType.GetForeignKeys().Single(); var baseIndex = dependentEntityType.FindIndex(baseFK.Properties); Assert.False(baseIndex.IsUnique); @@ -693,10 +708,17 @@ public virtual void Index_removed_when_covered_by_an_inherited_index() Assert.False(derivedDependentEntityType.GetDeclaredForeignKeys().Single().IsUnique); Assert.Empty(derivedDependentEntityType.GetDeclaredIndexes()); - Fixture.AssertEqual(initialProperties, derivedDependentEntityType.GetProperties()); - Fixture.AssertEqual(initialKeys, derivedDependentEntityType.GetKeys()); - Fixture.AssertEqual(initialIndexes, derivedDependentEntityType.GetIndexes()); - Fixture.AssertEqual(initialForeignKeys, derivedDependentEntityType.GetForeignKeys()); + Fixture.TestHelpers.ModelAsserter.AssertEqual(initialProperties, derivedDependentEntityType.GetProperties()); + Fixture.TestHelpers.ModelAsserter.AssertEqual(initialKeys, derivedDependentEntityType.GetKeys()); + Fixture.TestHelpers.ModelAsserter.AssertEqual(initialIndexes, derivedDependentEntityType.GetIndexes()); + Fixture.TestHelpers.ModelAsserter.AssertEqual(initialForeignKeys, derivedDependentEntityType.GetForeignKeys()); + + modelBuilder.FinalizeModel(); + + var indexRemoveMessage = + CoreResources.LogRedundantIndexRemoved(new TestLogger()).GenerateMessage( + "{'CustomerId'}", nameof(Order), "{'CustomerId', 'AnotherCustomerId'}"); + Assert.Equal(1, modelBuilder.ModelLoggerFactory.Log.Count(l => l.Message == indexRemoveMessage)); } [ConditionalFact] diff --git a/test/EFCore.Tests/ModelBuilding/ManyToManyTestBase.cs b/test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.ManyToMany.cs similarity index 100% rename from test/EFCore.Tests/ModelBuilding/ManyToManyTestBase.cs rename to test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.ManyToMany.cs diff --git a/test/EFCore.Tests/ModelBuilding/ManyToOneTestBase.cs b/test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.ManyToOne.cs similarity index 99% rename from test/EFCore.Tests/ModelBuilding/ManyToOneTestBase.cs rename to test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.ManyToOne.cs index a0e34fe7d36..5ef543d2e31 100644 --- a/test/EFCore.Tests/ModelBuilding/ManyToOneTestBase.cs +++ b/test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.ManyToOne.cs @@ -7,7 +7,7 @@ namespace Microsoft.EntityFrameworkCore.ModelBuilding; public abstract partial class ModelBuilderTest { - public abstract class ManyToOneTestBase: ModelBuilderTestBase + public abstract class ManyToOneTestBase : ModelBuilderTestBase { public ManyToOneTestBase(ModelBuilderFixtureBase fixture) : base(fixture) diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs b/test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.NonGeneric.cs similarity index 92% rename from test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs rename to test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.NonGeneric.cs index a784ea21f2c..74cdee97674 100644 --- a/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs +++ b/test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.NonGeneric.cs @@ -5,206 +5,12 @@ namespace Microsoft.EntityFrameworkCore.ModelBuilding; -public class ModelBuilderNonGenericTest : ModelBuilderTest +public abstract partial class ModelBuilderTest { - public class NonGenericNonRelationship : NonRelationshipTestBase - { - public NonGenericNonRelationship(ModelBuilderFixtureBase fixture) - : base(fixture) - { - } - - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new NonGenericTestModelBuilder(testHelpers, configure); - } - - public class NonGenericComplexType : ComplexTypeTestBase - { - public NonGenericComplexType(ModelBuilderFixtureBase fixture) - : base(fixture) - { - } - - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new NonGenericTestModelBuilder(testHelpers, configure); - } - - public class NonGenericInheritance : InheritanceTestBase - { - public NonGenericInheritance(ModelBuilderFixtureBase fixture) - : base(fixture) - { - } - - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new NonGenericTestModelBuilder(testHelpers, configure); - } - - public class NonGenericOwnedTypes : OwnedTypesTestBase - { - public NonGenericOwnedTypes(ModelBuilderFixtureBase fixture) - : base(fixture) - { - } - - [ConditionalFact] - public virtual void OwnsOne_HasOne_with_just_string_navigation_for_non_CLR_property_throws() - { - var modelBuilder = CreateModelBuilder(); - - Assert.Equal( - CoreStrings.NoClrNavigation("Snoop", nameof(Dre)), - Assert.Throws( - () => - ((NonGenericTestOwnedNavigationBuilder)modelBuilder.Entity().OwnsOne(e => e.Dre)) - .GetInfrastructure() - .HasOne("Snoop")).Message); - } - - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new NonGenericTestModelBuilder(testHelpers, configure); - } - - public class NonGenericOneToMany : OneToManyTestBase - { - public NonGenericOneToMany(ModelBuilderFixtureBase fixture) - : base(fixture) - { - } - - [ConditionalFact] - public virtual void HasOne_with_just_string_navigation_for_non_CLR_property_throws() - { - var modelBuilder = CreateModelBuilder(); - - Assert.Equal( - CoreStrings.NoClrNavigation("Snoop", nameof(Dr)), - Assert.Throws( - () => - ((NonGenericTestEntityTypeBuilder)modelBuilder.Entity()).GetInfrastructure() - .HasOne("Snoop")).Message); - } - - [ConditionalFact] - public virtual void HasMany_with_just_string_navigation_for_non_CLR_property_throws() - { - var modelBuilder = CreateModelBuilder(); - - Assert.Equal( - CoreStrings.NoClrNavigation("Snoop", nameof(Dr)), - Assert.Throws( - () => - ((NonGenericTestEntityTypeBuilder)modelBuilder.Entity()).GetInfrastructure() - .HasMany("Snoop")).Message); - } - - [ConditionalFact] - public virtual void HasMany_with_a_non_collection_just_string_navigation_CLR_property_throws() - { - var modelBuilder = CreateModelBuilder(); - - Assert.Equal( - CoreStrings.NavigationCollectionWrongClrType("Dre", nameof(Dr), nameof(Dre), "T"), - Assert.Throws( - () => - ((NonGenericTestEntityTypeBuilder)modelBuilder.Entity()).GetInfrastructure() - .HasMany("Dre")).Message); - } - - [ConditionalFact] //Issue#13108 - public virtual void HasForeignKey_infers_type_for_shadow_property_when_not_specified() - { - var modelBuilder = CreateModelBuilder(); - - modelBuilder.Entity( - e => - { - e.HasKey(c => c.Key); - ((NonGenericTestEntityTypeBuilder)e).GetInfrastructure().Property("ParentKey"); - e.HasOne(c => c.Parent).WithMany(c => c.Children).HasForeignKey("ParentKey"); - }); - - modelBuilder.Entity().HasKey(c => c.Key); - - var model = (IConventionModel)modelBuilder.FinalizeModel(); - - var property = model - .FindEntityType(typeof(ComplexCaseChild13108))!.GetProperties().Single(p => p.Name == "ParentKey"); - Assert.Equal(typeof(int), property.ClrType); - Assert.Equal(ConfigurationSource.Explicit, property.GetTypeConfigurationSource()); - } - - protected class ComplexCaseChild13108 - { - public int Key { get; set; } - public string? Id { get; set; } - private int ParentKey { get; set; } - public ComplexCaseParent13108? Parent { get; set; } - } - - protected class ComplexCaseParent13108 - { - public int Key { get; set; } - public string? Id { get; set; } - public ICollection? Children { get; set; } - } - - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new NonGenericTestModelBuilder(testHelpers, configure); - } - - public class NonGenericManyToOne : ManyToOneTestBase - { - public NonGenericManyToOne(ModelBuilderFixtureBase fixture) - : base(fixture) - { - } - - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new NonGenericTestModelBuilder(testHelpers, configure); - } - - public class NonGenericManyToMany : ManyToManyTestBase - { - public NonGenericManyToMany(ModelBuilderFixtureBase fixture) - : base(fixture) - { - } - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new NonGenericTestModelBuilder(testHelpers, configure); - } - - public class NonGenericOneToOne : OneToOneTestBase - { - public NonGenericOneToOne(ModelBuilderFixtureBase fixture) - : base(fixture) - { - } - - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new NonGenericTestModelBuilder(testHelpers, configure); - } - public class NonGenericTestModelBuilder : TestModelBuilder { - public NonGenericTestModelBuilder(TestHelpers testHelpers, Action? configure) - : base(testHelpers, configure) + public NonGenericTestModelBuilder(ModelBuilderFixtureBase fixture, Action? configure) + : base(fixture, configure) { } diff --git a/test/EFCore.Tests/ModelBuilding/NonRelationshipTestBase.cs b/test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.NonRelationship.cs similarity index 97% rename from test/EFCore.Tests/ModelBuilding/NonRelationshipTestBase.cs rename to test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.NonRelationship.cs index 0ab23940bd1..c8d176ba141 100644 --- a/test/EFCore.Tests/ModelBuilding/NonRelationshipTestBase.cs +++ b/test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.NonRelationship.cs @@ -844,22 +844,22 @@ public virtual void Properties_can_have_provider_type_set() var up = entityType.FindProperty("Up")!; Assert.Null(up.GetProviderClrType()); - Assert.IsType>(up.GetValueComparer()); + Assert.True(up.GetValueComparer()?.IsDefault()); var down = entityType.FindProperty("Down")!; Assert.Same(typeof(byte[]), down.GetProviderClrType()); - Assert.IsType>(down.GetValueComparer()); + Assert.True(down.GetValueComparer()?.IsDefault()); Assert.IsType>(down.GetProviderValueComparer()); var charm = entityType.FindProperty("Charm")!; Assert.Same(typeof(long), charm.GetProviderClrType()); Assert.IsType>(charm.GetValueComparer()); - Assert.IsType>(charm.GetProviderValueComparer()); + Assert.True(charm.GetProviderValueComparer()?.IsDefault()); var strange = entityType.FindProperty("Strange")!; Assert.Null(strange.GetProviderClrType()); - Assert.IsType>(strange.GetValueComparer()); - Assert.IsType>(strange.GetProviderValueComparer()); + Assert.True(strange.GetValueComparer()?.IsDefault()); + Assert.True(strange.GetProviderValueComparer()?.IsDefault()); var top = entityType.FindProperty("Top")!; Assert.Same(typeof(string), top.GetProviderClrType()); @@ -915,12 +915,12 @@ public virtual void Properties_can_have_non_generic_value_converter_set() var down = entityType.FindProperty("Down")!; Assert.Same(stringConverter, down.GetValueConverter()); - Assert.IsType>(down.GetValueComparer()); + Assert.True(down.GetValueComparer()?.IsDefault()); Assert.IsType>(down.GetProviderValueComparer()); var charm = entityType.FindProperty("Charm")!; Assert.Same(intConverter, charm.GetValueConverter()); - Assert.IsType>(charm.GetValueComparer()); + Assert.True(charm.GetValueComparer()?.IsDefault()); Assert.IsType>(charm.GetProviderValueComparer()); Assert.Null(entityType.FindProperty("Strange")!.GetValueConverter()); @@ -959,12 +959,12 @@ public virtual void Properties_can_have_custom_type_value_converter_type_set() var charm = entityType.FindProperty("Charm")!; Assert.IsType>(charm.GetValueConverter()); Assert.IsType>(charm.GetValueComparer()); - Assert.IsType>(charm.GetProviderValueComparer()); + Assert.True(charm.GetProviderValueComparer()?.IsDefault()); var strange = entityType.FindProperty("Strange")!; Assert.Null(strange.GetValueConverter()); - Assert.IsType>(strange.GetValueComparer()); - Assert.IsType>(strange.GetProviderValueComparer()); + Assert.True(strange.GetValueComparer()?.IsDefault()); + Assert.True(strange.GetProviderValueComparer()?.IsDefault()); } private class UTF8StringToBytesConverter : StringToBytesConverter @@ -1004,18 +1004,18 @@ public virtual void Properties_can_have_value_converter_set_inline() var up = entityType.FindProperty("Up")!; Assert.Null(up.GetProviderClrType()); Assert.Null(up.GetValueConverter()); - Assert.IsType>(up.GetValueComparer()); - Assert.IsType>(up.GetProviderValueComparer()); + Assert.True(up.GetValueComparer()?.IsDefault()); + Assert.True(up.GetProviderValueComparer()?.IsDefault()); var down = entityType.FindProperty("Down")!; Assert.IsType>(down.GetValueConverter()); - Assert.IsType>(down.GetValueComparer()); - Assert.IsType>(down.GetProviderValueComparer()); + Assert.True(down.GetValueComparer()?.IsDefault()); + Assert.True(down.GetProviderValueComparer()?.IsDefault()); var charm = entityType.FindProperty("Charm")!; Assert.IsType>(charm.GetValueConverter()); Assert.IsType>(charm.GetValueComparer()); - Assert.IsType>(charm.GetProviderValueComparer()); + Assert.True(charm.GetProviderValueComparer()?.IsDefault()); var strange = entityType.FindProperty("Strange")!; Assert.IsType>(strange.GetValueConverter()); @@ -1047,18 +1047,18 @@ public virtual void Properties_can_have_value_converter_set() var up = entityType.FindProperty("Up")!; Assert.Null(up.GetProviderClrType()); Assert.Null(up.GetValueConverter()); - Assert.IsType>(up.GetValueComparer()); - Assert.IsType>(up.GetProviderValueComparer()); + Assert.True(up.GetValueComparer()?.IsDefault()); + Assert.True(up.GetProviderValueComparer()?.IsDefault()); var down = entityType.FindProperty("Down")!; Assert.IsType>(down.GetValueConverter()); - Assert.IsType>(down.GetValueComparer()); - Assert.IsType>(down.GetProviderValueComparer()); + Assert.True(down.GetValueComparer()?.IsDefault()); + Assert.True(down.GetProviderValueComparer()?.IsDefault()); var charm = entityType.FindProperty("Charm")!; Assert.IsType>(charm.GetValueConverter()); Assert.IsType>(charm.GetValueComparer()); - Assert.IsType>(charm.GetProviderValueComparer()); + Assert.True(charm.GetProviderValueComparer()?.IsDefault()); var strange = entityType.FindProperty("Strange")!; Assert.IsType>(strange.GetValueConverter()); @@ -2060,18 +2060,18 @@ public virtual void Can_set_composite_key_on_an_entity_with_fields() [ConditionalFact] public virtual void Can_set_alternate_key_on_an_entity_with_fields() { - var modelBuilder = CreateTestModelBuilder(InMemoryTestHelpers.Instance); + var modelBuilder = CreateModelBuilder(); modelBuilder.Entity().HasAlternateKey(e => e.CompanyId); var entity = modelBuilder.Model.FindEntityType(typeof(EntityWithFields))!; - var properties = entity.GetProperties(); + var properties = entity.GetProperties().Where(p => !p.IsShadowProperty()); Assert.Single(properties); var property = properties.Single(); Assert.Equal(nameof(EntityWithFields.CompanyId), property.Name); Assert.Null(property.PropertyInfo); Assert.NotNull(property.FieldInfo); - var keys = entity.GetKeys(); + var keys = entity.GetKeys().Where(k => k.Properties.Any(p => p.Name.Contains("Id"))); var key = Assert.Single(keys); Assert.Equal(properties, key.Properties); } @@ -2079,11 +2079,12 @@ public virtual void Can_set_alternate_key_on_an_entity_with_fields() [ConditionalFact] public virtual void Can_set_composite_alternate_key_on_an_entity_with_fields() { - var modelBuilder = CreateTestModelBuilder(InMemoryTestHelpers.Instance); + var modelBuilder = CreateModelBuilder(); modelBuilder.Entity().HasAlternateKey(e => new { e.TenantId, e.CompanyId }); - var keys = modelBuilder.Model.FindEntityType(typeof(EntityWithFields))!.GetKeys(); + var keys = modelBuilder.Model.FindEntityType(typeof(EntityWithFields))!.GetKeys() + .Where(k => k.Properties.Any(p => p.Name.Contains("Id"))); Assert.Single(keys); var properties = keys.Single().Properties; Assert.Equal(2, properties.Count); @@ -2100,12 +2101,12 @@ public virtual void Can_set_composite_alternate_key_on_an_entity_with_fields() [ConditionalFact] public virtual void Can_call_Property_on_an_entity_with_fields() { - var modelBuilder = CreateTestModelBuilder(InMemoryTestHelpers.Instance); + var modelBuilder = CreateModelBuilder(); modelBuilder.Entity().Property(e => e.Id); var model = modelBuilder.FinalizeModel(); - var properties = model.FindEntityType(typeof(EntityWithFields))!.GetProperties(); + var properties = model.FindEntityType(typeof(EntityWithFields))!.GetProperties().Where(p => !p.IsShadowProperty()); var property = Assert.Single(properties); Assert.Equal(nameof(EntityWithFields.Id), property.Name); Assert.Null(property.PropertyInfo); @@ -2152,7 +2153,7 @@ public virtual void Can_set_composite_index_on_an_entity_with_fields() [ConditionalFact] public virtual void Can_ignore_a_field_on_an_entity_with_fields() { - var modelBuilder = CreateTestModelBuilder(InMemoryTestHelpers.Instance); + var modelBuilder = CreateModelBuilder(); modelBuilder.Entity() .Ignore(e => e.CompanyId) @@ -2160,14 +2161,14 @@ public virtual void Can_ignore_a_field_on_an_entity_with_fields() var model = modelBuilder.FinalizeModel(); var entity = model.FindEntityType(typeof(EntityWithFields))!; - var property = Assert.Single(entity.GetProperties()); + var property = Assert.Single(entity.GetProperties().Where(p => !p.IsShadowProperty())); Assert.Equal(nameof(EntityWithFields.Id), property.Name); } [ConditionalFact] public virtual void Can_ignore_a_field_on_a_keyless_entity_with_fields() { - var modelBuilder = CreateTestModelBuilder(InMemoryTestHelpers.Instance); + var modelBuilder = CreateModelBuilder(); modelBuilder.Entity() .HasNoKey() @@ -2176,7 +2177,7 @@ public virtual void Can_ignore_a_field_on_a_keyless_entity_with_fields() var model = modelBuilder.FinalizeModel(); var entity = model.FindEntityType(typeof(KeylessEntityWithFields))!; - var property = Assert.Single(entity.GetProperties()); + var property = Assert.Single(entity.GetProperties().Where(p => !p.IsShadowProperty())); Assert.Equal(nameof(KeylessEntityWithFields.LastName), property.Name); } @@ -3013,7 +3014,7 @@ public virtual void Can_set_composite_key_for_primitive_collection_on_an_entity_ [ConditionalFact] public virtual void Can_set_alternate_key_for_primitive_collection_on_an_entity_with_fields() { - var modelBuilder = CreateTestModelBuilder(InMemoryTestHelpers.Instance); + var modelBuilder = CreateModelBuilder(); modelBuilder.Entity( b => @@ -3040,7 +3041,7 @@ public virtual void Can_set_alternate_key_for_primitive_collection_on_an_entity_ [ConditionalFact] public virtual void Can_call_PrimitiveCollection_on_an_entity_with_fields() { - var modelBuilder = CreateTestModelBuilder(InMemoryTestHelpers.Instance); + var modelBuilder = CreateModelBuilder(); modelBuilder.Entity().PrimitiveCollection(e => e.CollectionId); modelBuilder.Entity().HasKey(e => e.CollectionId); @@ -3302,11 +3303,11 @@ public virtual void Element_types_can_have_provider_type_set() var up = entityType.FindProperty("Up")!.GetElementType()!; Assert.Null(up.GetProviderClrType()); - Assert.IsType>(up.GetValueComparer()); + Assert.True(up.GetValueComparer()?.IsDefault()); var down = entityType.FindProperty("Down")!.GetElementType()!; Assert.Same(typeof(byte[]), down.GetProviderClrType()); - Assert.IsType>(down.GetValueComparer()); + Assert.True(down.GetValueComparer()?.IsDefault()); var charm = entityType.FindProperty("Charm")!.GetElementType()!; Assert.Same(typeof(long), charm.GetProviderClrType()); @@ -3314,7 +3315,7 @@ public virtual void Element_types_can_have_provider_type_set() var strange = entityType.FindProperty("Strange")!.GetElementType()!; Assert.Null(strange.GetProviderClrType()); - Assert.IsType>(strange.GetValueComparer()); + Assert.True(strange.GetValueComparer()?.IsDefault()); var top = entityType.FindProperty("Top")!.GetElementType()!; Assert.Same(typeof(string), top.GetProviderClrType()); @@ -3346,11 +3347,11 @@ public virtual void Element_types_can_have_non_generic_value_converter_set() var down = entityType.FindProperty("Down")!.GetElementType()!; Assert.Same(stringConverter, down.GetValueConverter()); - Assert.IsType>(down.GetValueComparer()); + Assert.True(down.GetValueComparer()?.IsDefault()); var charm = entityType.FindProperty("Charm")!.GetElementType()!; Assert.Same(intConverter, charm.GetValueConverter()); - Assert.IsType>(charm.GetValueComparer()); + Assert.True(charm.GetValueComparer()?.IsDefault()); Assert.Null(entityType.FindProperty("Strange")!.GetElementType()!.GetValueConverter()); } @@ -3392,7 +3393,7 @@ public virtual void Element_types_can_have_custom_type_value_converter_type_set( var strange = entityType.FindProperty("Strange")!.GetElementType()!; Assert.Null(strange.GetValueConverter()); - Assert.IsType>(strange.GetValueComparer()); + Assert.True(strange.GetValueComparer()?.IsDefault()); var top = entityType.FindProperty("Top")!.GetElementType()!; Assert.Null(top.GetValueConverter()); @@ -3422,11 +3423,11 @@ public virtual void Primitive_collections_can_have_value_converter_set() var up = entityType.FindProperty("Up")!.GetElementType()!; Assert.Null(up.GetProviderClrType()); Assert.Null(up.GetValueConverter()); - Assert.IsType>(up.GetValueComparer()); + Assert.True(up.GetValueComparer()?.IsDefault()); var down = entityType.FindProperty("Down")!.GetElementType()!; Assert.IsType>(down.GetValueConverter()); - Assert.IsType>(down.GetValueComparer()); + Assert.True(down.GetValueComparer()?.IsDefault()); var charm = entityType.FindProperty("Charm")!.GetElementType()!; Assert.IsType>(charm.GetValueConverter()); diff --git a/test/EFCore.Tests/ModelBuilding/OneToManyTestBase.cs b/test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.OneToMany.cs similarity index 100% rename from test/EFCore.Tests/ModelBuilding/OneToManyTestBase.cs rename to test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.OneToMany.cs diff --git a/test/EFCore.Tests/ModelBuilding/OneToOneTestBase.cs b/test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.OneToOne.cs similarity index 100% rename from test/EFCore.Tests/ModelBuilding/OneToOneTestBase.cs rename to test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.OneToOne.cs diff --git a/test/EFCore.Tests/ModelBuilding/OwnedTypesTestBase.cs b/test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.OwnedTypes.cs similarity index 100% rename from test/EFCore.Tests/ModelBuilding/OwnedTypesTestBase.cs rename to test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.OwnedTypes.cs diff --git a/test/EFCore.Tests/ModelBuilding/TestModel.cs b/test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.TestModel.cs similarity index 100% rename from test/EFCore.Tests/ModelBuilding/TestModel.cs rename to test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.TestModel.cs diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs b/test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.cs similarity index 50% rename from test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs rename to test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.cs index e6b64f3960c..3043c0e445a 100644 --- a/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs +++ b/test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.cs @@ -4,14 +4,13 @@ #nullable enable using Microsoft.EntityFrameworkCore.Diagnostics.Internal; -using Microsoft.EntityFrameworkCore.Metadata.Internal; // ReSharper disable InconsistentNaming namespace Microsoft.EntityFrameworkCore.ModelBuilding; public abstract partial class ModelBuilderTest { - public abstract class ModelBuilderTestBase : IClassFixture + public abstract class ModelBuilderTestBase { protected ModelBuilderTestBase(ModelBuilderFixtureBase fixture) { @@ -20,28 +19,23 @@ protected ModelBuilderTestBase(ModelBuilderFixtureBase fixture) protected virtual ModelBuilderFixtureBase Fixture { get; } - protected virtual TestModelBuilder CreateModelBuilder(Action? configure = null) - => CreateTestModelBuilder(InMemoryTestHelpers.Instance, configure); - - protected abstract TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure = null); + protected abstract TestModelBuilder CreateModelBuilder(Action? configure = null); public virtual void AssertEqual( IReadOnlyModel expected, IReadOnlyModel actual, bool compareAnnotations = false) - => Fixture.AssertEqual(expected, actual, compareAnnotations); + => Fixture.TestHelpers.ModelAsserter.AssertEqual(expected, actual, compareAnnotations); public virtual void AssertEqual( IEnumerable expectedProperties, IEnumerable actualProperties, bool assertOrder = false, bool compareAnnotations = false) - => Fixture.AssertEqual(expectedProperties, actualProperties, assertOrder, compareAnnotations); + => Fixture.TestHelpers.ModelAsserter.AssertEqual(expectedProperties, actualProperties, assertOrder, compareAnnotations); public virtual IReadOnlyModel Clone(IReadOnlyModel model) - => Fixture.Clone(model); + => Fixture.TestHelpers.ModelAsserter.Clone(model); protected TestModelBuilder HobNobBuilder() { @@ -54,1022 +48,18 @@ protected TestModelBuilder HobNobBuilder() } } - public class ModelBuilderFixtureBase + public abstract class ModelBuilderFixtureBase { - public virtual void AssertEqual( - IReadOnlyModel expected, - IReadOnlyModel actual, - bool compareAnnotations = false) - => AssertEqual( - expected, - actual, - compareAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), - compareAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), - compareMemberAnnotations: compareAnnotations); - - public virtual bool AssertEqual(IReadOnlyModel expected, IReadOnlyModel actual, - IEnumerable expectedAnnotations, IEnumerable actualAnnotations, - bool compareMemberAnnotations = false) - { - expectedAnnotations = expectedAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); - actualAnnotations = actualAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); - - Assert.Multiple( - () => Assert.Equal(expected.ModelId, actual.ModelId), - () => Assert.Equal(expected.GetProductVersion(), actual.GetProductVersion()), - () => Assert.Equal(expected.GetPropertyAccessMode(), actual.GetPropertyAccessMode()), - () => Assert.Equal(expected.GetChangeTrackingStrategy(), actual.GetChangeTrackingStrategy()), - () => AssertEqual(expected.GetEntityTypes(), actual.GetEntityTypes(), - assertOrder: true, compareAnnotations: compareMemberAnnotations), - () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); - - return true; - } - - public virtual void AssertEqual( - IEnumerable expectedEntityTypes, - IEnumerable actualEntityTypes, - bool assertOrder = false, - bool compareAnnotations = false) - { - if (!assertOrder) - { - expectedEntityTypes = expectedEntityTypes.OrderBy(p => p.Name); - actualEntityTypes = actualEntityTypes.OrderBy(p => p.Name); - } - - Assert.Equal(expectedEntityTypes, actualEntityTypes, - (expected, actual) => - AssertEqual( - expected, - actual, - compareAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), - compareAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), - compareBackreferences: false, - compareMemberAnnotations: compareAnnotations)); - } - - public virtual bool AssertEqual(IReadOnlyEntityType? expected, IReadOnlyEntityType? actual, - IEnumerable expectedAnnotations, IEnumerable actualAnnotations, - bool compareBackreferences = false, bool compareMemberAnnotations = false) - { - if (expected == null) - { - Assert.Null(actual); - - return true; - } - - Assert.NotNull(actual); - - expectedAnnotations = expectedAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); - actualAnnotations = actualAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); - - Assert.Multiple( - () => Assert.Equal(expected.Name, actual.Name), - () => Assert.Equal(expected.ClrType, actual.ClrType), - () => Assert.Equal(expected.HasSharedClrType, actual.HasSharedClrType), - () => Assert.Equal(expected.IsPropertyBag, actual.IsPropertyBag), - () => Assert.Equal(expected.GetQueryFilter(), actual.GetQueryFilter()), - () => Assert.Equal(expected.GetSeedData(), actual.GetSeedData()), - () => Assert.Equal(expected.GetPropertyAccessMode(), actual.GetPropertyAccessMode()), - () => Assert.Equal(expected.GetChangeTrackingStrategy(), actual.GetChangeTrackingStrategy()), - () => Assert.Equal(expected.GetDiscriminatorPropertyName(), actual.GetDiscriminatorPropertyName()), - () => Assert.Equal(expected.GetDiscriminatorValue(), actual.GetDiscriminatorValue()), - () => Assert.Equal(expected.GetIsDiscriminatorMappingComplete(), actual.GetIsDiscriminatorMappingComplete()), - () => AssertEqual(expected.GetProperties(), actual.GetProperties(), - assertOrder: true, compareAnnotations: compareMemberAnnotations), - () => AssertEqual(expected.GetServiceProperties(), actual.GetServiceProperties(), - assertOrder: true, compareAnnotations: compareMemberAnnotations), - () => AssertEqual(expected.GetSkipNavigations(), actual.GetSkipNavigations(), - assertOrder: true, compareAnnotations: compareMemberAnnotations), - () => AssertEqual(expected.GetForeignKeys(), actual.GetForeignKeys(), - assertOrder: true, compareAnnotations: compareMemberAnnotations), - () => AssertEqual(expected.GetKeys(), actual.GetKeys(), - assertOrder: true, compareAnnotations: compareMemberAnnotations), - () => AssertEqual(expected.GetIndexes(), actual.GetIndexes(), - assertOrder: true, compareAnnotations: compareMemberAnnotations), - () => AssertEqual(expected.GetComplexProperties(), actual.GetComplexProperties(), - assertOrder: true, compareAnnotations: compareMemberAnnotations), - () => - { - if (compareBackreferences) - { - Assert.Equal(expected.BaseType?.Name, actual.BaseType?.Name); - } - }, - () => - { - if (compareBackreferences) - { - Assert.Equal(expected.GetReferencingForeignKeys(), actual.GetReferencingForeignKeys()); - } - }, - () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); - - return true; - } - - public virtual bool AssertEqual(IReadOnlyComplexType expected, IReadOnlyComplexType actual, - IEnumerable expectedAnnotations, IEnumerable actualAnnotations, - bool compareBackreferences = false, - bool compareMemberAnnotations = false) - { - expectedAnnotations = expectedAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); - actualAnnotations = actualAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); - - Assert.Multiple( - () => Assert.Equal(expected.Name, actual.Name), - () => Assert.Equal(expected.ClrType, actual.ClrType), - () => Assert.Equal(expected.GetPropertyAccessMode(), actual.GetPropertyAccessMode()), - () => Assert.Equal(expected.GetChangeTrackingStrategy(), actual.GetChangeTrackingStrategy()), - () => AssertEqual(expected.GetProperties(), actual.GetProperties(), - assertOrder: true, compareAnnotations: compareMemberAnnotations), - () => AssertEqual(expected.GetComplexProperties(), actual.GetComplexProperties(), - assertOrder: true, compareAnnotations: compareMemberAnnotations), - () => - { - if (compareBackreferences) - { - Assert.Equal(expected.ContainingEntityType.Name, actual.ContainingEntityType.Name); - } - }, - () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); - - return true; - } - - public virtual void AssertEqual( - IEnumerable expectedProperties, - IEnumerable actualProperties, - bool assertOrder = false, - bool compareAnnotations = false) - { - if (!assertOrder) - { - expectedProperties = expectedProperties.OrderBy(p => p.Name); - actualProperties = actualProperties.OrderBy(p => p.Name); - } - - Assert.Equal(expectedProperties, actualProperties, - (expected, actual) => - AssertEqual( - expected, - actual, - compareAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), - compareAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), - compareBackreferences: false, - compareMemberAnnotations: compareAnnotations)); - } - - public virtual bool AssertEqual(IReadOnlyComplexProperty? expected, IReadOnlyComplexProperty? actual, - IEnumerable expectedAnnotations, IEnumerable actualAnnotations, - bool compareBackreferences = false, - bool compareMemberAnnotations = false) - { - if (expected == null) - { - Assert.Null(actual); - - return true; - } - - Assert.NotNull(actual); - - expectedAnnotations = expectedAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); - actualAnnotations = actualAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); - - Assert.Multiple( - () => Assert.Equal(expected.Name, actual.Name), - () => Assert.Equal(expected.ClrType, actual.ClrType), - () => Assert.Equal(expected.FieldInfo, actual.FieldInfo), - () => Assert.Equal(expected.GetIdentifyingMemberInfo(), actual.GetIdentifyingMemberInfo()), - () => Assert.Equal(expected.IsShadowProperty(), actual.IsShadowProperty()), - () => Assert.Equal(expected.IsNullable, actual.IsNullable), - () => Assert.Equal(expected.Sentinel, actual.Sentinel), - () => Assert.Equal(expected.GetPropertyAccessMode(), actual.GetPropertyAccessMode()), - () => AssertEqual(expected.ComplexType, actual.ComplexType, - compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), - compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), - compareBackreferences: false, - compareMemberAnnotations: compareMemberAnnotations), - () => - { - if (compareBackreferences) - { - Assert.Equal(expected.DeclaringType.Name, actual.DeclaringType.Name); - } - }, - () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); - - return true; - } - - public virtual void AssertEqual( - IEnumerable expectedProperties, - IEnumerable actualProperties, - bool assertOrder = false, - bool compareAnnotations = false) - { - if (!assertOrder) - { - expectedProperties = expectedProperties.OrderBy(p => p.Name); - actualProperties = actualProperties.OrderBy(p => p.Name); - } - - Assert.Equal(expectedProperties, actualProperties, - (expected, actual) => - AssertEqual( - expected, - actual, - compareAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), - compareAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), - compareBackreferences: false)); - } - - public virtual bool AssertEqual(IReadOnlyProperty? expected, IReadOnlyProperty? actual, - IEnumerable expectedAnnotations, IEnumerable actualAnnotations, - bool compareBackreferences = false) - { - if (expected == null) - { - Assert.Null(actual); - - return true; - } - - Assert.NotNull(actual); - - expectedAnnotations = expectedAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); - actualAnnotations = actualAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); - - Assert.Multiple( - () => Assert.Equal(expected.Name, actual.Name), - () => Assert.Equal(expected.ClrType, actual.ClrType), - () => Assert.Equal(expected.FieldInfo?.Name, actual.FieldInfo?.Name), - () => Assert.Equal(expected.GetIdentifyingMemberInfo()?.Name, actual.GetIdentifyingMemberInfo()?.Name), - () => Assert.Equal(expected.IsShadowProperty(), actual.IsShadowProperty()), - () => Assert.Equal(expected.IsNullable, actual.IsNullable), - () => Assert.Equal(expected.IsConcurrencyToken, actual.IsConcurrencyToken), - () => Assert.Equal(expected.Sentinel, actual.Sentinel), - () => Assert.Equal(expected.ValueGenerated, actual.ValueGenerated), - () => Assert.Equal(expected.GetPropertyAccessMode(), actual.GetPropertyAccessMode()), - () => Assert.Equal(expected.GetBeforeSaveBehavior(), actual.GetBeforeSaveBehavior()), - () => Assert.Equal(expected.GetAfterSaveBehavior(), actual.GetAfterSaveBehavior()), - () => - { - if (actual.Name != (actual.DeclaringType as IEntityType)?.GetDiscriminatorPropertyName()) - { - Assert.Equal(expected.GetMaxLength(), actual.GetMaxLength()); - } - }, - () => Assert.Equal(expected.GetPrecision(), actual.GetPrecision()), - () => Assert.Equal(expected.GetScale(), actual.GetScale()), - () => Assert.Equal(expected.IsUnicode(), actual.IsUnicode()), - () => Assert.Equal(expected.GetProviderClrType(), actual.GetProviderClrType()), - () => Assert.Equal(expected.GetValueConverter()?.GetType(), actual.GetValueConverter()?.GetType()), - () => Assert.Equal(expected.IsKey(), actual.IsKey()), - () => Assert.Equal(expected.IsForeignKey(), actual.IsForeignKey()), - () => Assert.Equal(expected.IsIndex(), actual.IsIndex()), - () => - { - if (compareBackreferences) - { - Assert.Equal(expected.DeclaringType.Name, actual.DeclaringType.Name); - } - }, - () => - { - if (compareBackreferences) - { - Assert.Equal(expected.GetContainingForeignKeys(), actual.GetContainingForeignKeys(), ForeignKeyComparer.Instance); - } - }, - () => - { - if (compareBackreferences) - { - Assert.Equal(expected.GetContainingIndexes(), actual.GetContainingIndexes(), IndexComparer.Instance); - } - }, - () => - { - if (compareBackreferences) - { - Assert.Equal(expected.GetContainingKeys(), actual.GetContainingKeys(), KeyComparer.Instance); - } - }, - () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); - - return true; - } - - public virtual void AssertEqual( - IEnumerable expectedProperties, - IEnumerable actualProperties, - bool assertOrder = false, - bool compareAnnotations = false) - { - if (!assertOrder) - { - expectedProperties = expectedProperties.OrderBy(p => p.Name); - actualProperties = actualProperties.OrderBy(p => p.Name); - } - - Assert.Equal(expectedProperties, actualProperties, - (expected, actual) => - AssertEqual( - expected, - actual, - compareAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), - compareAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), - compareBackreferences: false)); - } - - public virtual bool AssertEqual(IReadOnlyServiceProperty? expected, IReadOnlyServiceProperty? actual, - IEnumerable expectedAnnotations, IEnumerable actualAnnotations, - bool compareBackreferences = false) - { - if (expected == null) - { - Assert.Null(actual); - - return true; - } - - Assert.NotNull(actual); - - expectedAnnotations = expectedAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); - actualAnnotations = actualAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); - - Assert.Multiple( - () => Assert.Equal(expected.Name, actual.Name), - () => Assert.Equal(expected.ClrType, actual.ClrType), - () => Assert.Equal(expected.FieldInfo, actual.FieldInfo), - () => Assert.Equal(expected.GetIdentifyingMemberInfo(), actual.GetIdentifyingMemberInfo()), - () => Assert.Equal(expected.IsShadowProperty(), actual.IsShadowProperty()), - () => Assert.Equal(expected.Sentinel, actual.Sentinel), - () => Assert.Equal(expected.GetPropertyAccessMode(), actual.GetPropertyAccessMode()), - () => - { - if (compareBackreferences) - { - Assert.Equal(expected.DeclaringType.Name, actual.DeclaringType.Name); - } - }, - () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); - - return true; - } - - public virtual void AssertEqual( - IEnumerable expectedNavigations, - IEnumerable actualNavigations, - bool assertOrder = false, - bool compareAnnotations = false) - { - if (!assertOrder) - { - expectedNavigations = expectedNavigations.OrderBy(p => p.Name); - actualNavigations = actualNavigations.OrderBy(p => p.Name); - } - - Assert.Equal(expectedNavigations, actualNavigations, - (expected, actual) => - AssertEqual( - expected, - actual, - compareAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), - compareAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), - compareBackreferences: false)); - } - - public virtual bool AssertEqual(IReadOnlyNavigation? expected, IReadOnlyNavigation? actual, - IEnumerable expectedAnnotations, IEnumerable actualAnnotations, - bool compareBackreferences = false) - { - if (expected == null) - { - Assert.Null(actual); - - return true; - } - - Assert.NotNull(actual); - - expectedAnnotations = expectedAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); - actualAnnotations = actualAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); - - Assert.Multiple( - () => Assert.Equal(expected.Name, actual.Name), - () => Assert.Equal(expected.ClrType, actual.ClrType), - () => Assert.Equal(expected.FieldInfo, actual.FieldInfo), - () => Assert.Equal(expected.GetIdentifyingMemberInfo(), actual.GetIdentifyingMemberInfo()), - () => Assert.Equal(expected.IsShadowProperty(), actual.IsShadowProperty()), - () => Assert.Equal(expected.IsCollection, actual.IsCollection), - () => Assert.Equal(expected.IsEagerLoaded, actual.IsEagerLoaded), - () => Assert.Equal(expected.LazyLoadingEnabled, actual.LazyLoadingEnabled), - () => Assert.Equal(expected.Sentinel, actual.Sentinel), - () => Assert.Equal(expected.GetPropertyAccessMode(), actual.GetPropertyAccessMode()), - () => - { - if (compareBackreferences) - { - Assert.Equal(expected.DeclaringType.Name, actual.DeclaringType.Name); - } - }, - () => - { - if (compareBackreferences) - { - Assert.Equal(expected.ForeignKey, actual.ForeignKey, ForeignKeyComparer.Instance); - } - }, - () => - { - if (compareBackreferences) - { - Assert.Equal(expected.Inverse?.Name, actual.Inverse?.Name); - } - }, - () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); - - return true; - } - - public virtual void AssertEqual( - IEnumerable expectedNavigations, - IEnumerable actualNavigations, - bool assertOrder = false, - bool compareAnnotations = false) - { - if (!assertOrder) - { - expectedNavigations = expectedNavigations.OrderBy(p => p.Name); - actualNavigations = actualNavigations.OrderBy(p => p.Name); - } - - Assert.Equal(expectedNavigations, actualNavigations, - (expected, actual) => - AssertEqual( - expected, - actual, - compareAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), - compareAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), - compareBackreferences: false)); - } - - public virtual bool AssertEqual(IReadOnlySkipNavigation expected, IReadOnlySkipNavigation actual, - IEnumerable expectedAnnotations, IEnumerable actualAnnotations, - bool compareBackreferences = false) - { - if (expected == null) - { - Assert.Null(actual); - - return true; - } - - Assert.NotNull(actual); - - expectedAnnotations = expectedAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); - actualAnnotations = actualAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); - - Assert.Multiple( - () => Assert.Equal(expected.Name, actual.Name), - () => Assert.Equal(expected.ClrType, actual.ClrType), - () => Assert.Equal(expected.FieldInfo, actual.FieldInfo), - () => Assert.Equal(expected.GetIdentifyingMemberInfo(), actual.GetIdentifyingMemberInfo()), - () => Assert.Equal(expected.IsShadowProperty(), actual.IsShadowProperty()), - () => Assert.Equal(expected.IsCollection, actual.IsCollection), - () => Assert.Equal(expected.IsEagerLoaded, actual.IsEagerLoaded), - () => Assert.Equal(expected.LazyLoadingEnabled, actual.LazyLoadingEnabled), - () => Assert.Equal(expected.Sentinel, actual.Sentinel), - () => Assert.Equal(expected.GetPropertyAccessMode(), actual.GetPropertyAccessMode()), - () => - { - if (compareBackreferences) - { - Assert.Equal(expected.DeclaringType.Name, actual.DeclaringType.Name); - } - }, - () => - { - if (compareBackreferences) - { - Assert.Equal(expected.ForeignKey!, actual.ForeignKey!, ForeignKeyComparer.Instance); - } - }, - () => - { - if (compareBackreferences) - { - Assert.Equal(expected.Inverse?.Name, actual.Inverse?.Name); - } - }, - () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); - - return true; - } - - public virtual void AssertEqual( - IEnumerable expectedKeys, - IEnumerable actualKeys, - bool assertOrder = false, - bool compareAnnotations = false) - { - if (!assertOrder) - { - expectedKeys = expectedKeys.Order(KeyComparer.Instance); - actualKeys = actualKeys.Order(KeyComparer.Instance); - } - - Assert.Equal(expectedKeys, actualKeys, - (expected, actual) => - AssertEqual( - expected, - actual, - compareAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), - compareAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), - compareBackreferences: false)); - } - - public virtual bool AssertEqual(IReadOnlyKey expected, IReadOnlyKey actual, - IEnumerable expectedAnnotations, IEnumerable actualAnnotations, - bool compareBackreferences = false) - { - if (expected == null) - { - Assert.Null(actual); - - return true; - } - - Assert.NotNull(actual); - - expectedAnnotations = expectedAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); - actualAnnotations = actualAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); - - Assert.Multiple( - () => - { - if (compareBackreferences) - { - Assert.Equal(expected, actual, KeyComparer.Instance); - } - else - { - Assert.Equal(expected.Properties, actual.Properties, PropertyListComparer.Instance); - } - }, - () => Assert.Equal(expected.IsPrimaryKey(), actual.IsPrimaryKey()), - () => - { - if (compareBackreferences) - { - Assert.Equal(expected.DeclaringEntityType.Name, actual.DeclaringEntityType.Name); - } - }, - () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); - - return true; - } - - public virtual void AssertEqual( - IEnumerable expectedForeignKey, - IEnumerable actualForeignKey, - bool assertOrder = false, - bool compareAnnotations = false) - { - if (!assertOrder) - { - expectedForeignKey = expectedForeignKey.Order(ForeignKeyComparer.Instance); - actualForeignKey = actualForeignKey.Order(ForeignKeyComparer.Instance); - } - - Assert.Equal(expectedForeignKey, actualForeignKey, - (expected, actual) => - AssertEqual( - expected, - actual, - compareAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), - compareAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), - compareBackreferences: false, - compareMemberAnnotations: compareAnnotations)); - } - - public virtual bool AssertEqual(IReadOnlyForeignKey expected, IReadOnlyForeignKey actual, - IEnumerable expectedAnnotations, IEnumerable actualAnnotations, - bool compareBackreferences = false, - bool compareMemberAnnotations = false) - { - if (expected == null) - { - Assert.Null(actual); - - return true; - } - - Assert.NotNull(actual); - - expectedAnnotations = expectedAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); - actualAnnotations = actualAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); - - Assert.Multiple( - () => - { - if (compareBackreferences) - { - Assert.Equal(expected, actual, ForeignKeyComparer.Instance); - } - else - { - Assert.Equal(expected.Properties, actual.Properties, PropertyListComparer.Instance); - Assert.Equal(expected.PrincipalKey.Properties, actual.PrincipalKey.Properties, PropertyListComparer.Instance); - } - }, - () => Assert.Equal(expected.IsRequired, actual.IsRequired), - () => Assert.Equal(expected.IsRequiredDependent, actual.IsRequiredDependent), - () => Assert.Equal(expected.IsUnique, actual.IsUnique), - () => Assert.Equal(expected.DeleteBehavior, actual.DeleteBehavior), - () => AssertEqual(expected.DependentToPrincipal, actual.DependentToPrincipal, - compareMemberAnnotations - ? expected.DependentToPrincipal?.GetAnnotations() ?? Enumerable.Empty() - : Enumerable.Empty(), - compareMemberAnnotations - ? actual.DependentToPrincipal?.GetAnnotations() ?? Enumerable.Empty() - : Enumerable.Empty(), - compareBackreferences: true), - () => AssertEqual(expected.PrincipalToDependent, actual.PrincipalToDependent, - compareMemberAnnotations - ? expected.PrincipalToDependent?.GetAnnotations() ?? Enumerable.Empty() - : Enumerable.Empty(), - compareMemberAnnotations - ? actual.PrincipalToDependent?.GetAnnotations() ?? Enumerable.Empty() - : Enumerable.Empty(), - compareBackreferences: true), - () => - { - if (compareBackreferences) - { - Assert.Equal(expected.DeclaringEntityType.Name, actual.DeclaringEntityType.Name); - } - }, - () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); - - return true; - } - - public virtual void AssertEqual( - IEnumerable expectedIndex, - IEnumerable actualIndex, - bool assertOrder = false, - bool compareAnnotations = false) - { - if (!assertOrder) - { - expectedIndex = expectedIndex.Order(IndexComparer.Instance); - actualIndex = actualIndex.Order(IndexComparer.Instance); - } - - Assert.Equal(expectedIndex, actualIndex, - (expected, actual) => - AssertEqual( - expected, - actual, - compareAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), - compareAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), - compareBackreferences: false)); - } - - public virtual bool AssertEqual(IReadOnlyIndex expected, IReadOnlyIndex actual, - IEnumerable expectedAnnotations, IEnumerable actualAnnotations, - bool compareBackreferences = false) - { - if (expected == null) - { - Assert.Null(actual); - - return true; - } - - Assert.NotNull(actual); - - expectedAnnotations = expectedAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); - actualAnnotations = actualAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); - - Assert.Multiple( - () => - { - if (compareBackreferences) - { - Assert.Equal(expected, actual, IndexComparer.Instance); - } - else - { - Assert.Equal(expected.Properties, actual.Properties, PropertyListComparer.Instance); - } - }, - () => Assert.Equal(expected.IsDescending, actual.IsDescending), - () => Assert.Equal(expected.IsUnique, actual.IsUnique), - () => Assert.Equal(expected.Name, actual.Name), - () => - { - if (compareBackreferences) - { - Assert.Equal(expected.DeclaringEntityType.Name, actual.DeclaringEntityType.Name); - } - }, - () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); - - return true; - } - - public virtual IReadOnlyModel Clone(IReadOnlyModel model) - { - IMutableModel modelClone = new Model(model.ModelId); - modelClone.SetChangeTrackingStrategy(model.GetChangeTrackingStrategy()); - - if (model.GetProductVersion() is string productVersion) - { - modelClone.SetProductVersion(productVersion); - } - - modelClone.SetPropertyAccessMode(model.GetPropertyAccessMode()); - modelClone.AddAnnotations(model.GetAnnotations().Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name))); - - var clonedEntityTypes = new Dictionary(); - foreach (var entityType in ((IModel)model).GetEntityTypesInHierarchicalOrder()) - { - var clonedEntityType = entityType.HasSharedClrType - ? modelClone.AddEntityType(entityType.Name, entityType.ClrType) - : modelClone.AddEntityType(entityType.ClrType); - - Copy(entityType, clonedEntityType); - clonedEntityTypes.Add(entityType, clonedEntityType); - } - - foreach (var clonedEntityType in clonedEntityTypes) - { - var targetEntityType = clonedEntityType.Value; - foreach (var foreignKey in clonedEntityType.Key.GetDeclaredForeignKeys()) - { - var targetPrincipalEntityType = targetEntityType.Model.FindEntityType(foreignKey.PrincipalEntityType.Name)!; - var clonedForeignKey = targetEntityType.AddForeignKey( - foreignKey.Properties.Select(p => targetEntityType.FindProperty(p.Name)!).ToList(), - targetPrincipalEntityType.FindKey( - foreignKey.PrincipalKey.Properties.Select(p => targetPrincipalEntityType.FindProperty(p.Name)!).ToList())!, - targetPrincipalEntityType); - Copy(foreignKey, clonedForeignKey); - } - } - - foreach (var clonedEntityType in clonedEntityTypes) - { - foreach (var skipNavigation in clonedEntityType.Key.GetDeclaredSkipNavigations()) - { - var targetEntityType = clonedEntityType.Value; - var otherEntityType = targetEntityType.Model.FindEntityType(skipNavigation.TargetEntityType.Name)!; - Copy(skipNavigation, clonedEntityType.Value.AddSkipNavigation( - skipNavigation.Name, - skipNavigation.GetIdentifyingMemberInfo(), - otherEntityType, - skipNavigation.IsCollection, - skipNavigation.IsOnDependent)); - } - } - - return modelClone; - } - - protected virtual void Copy(IReadOnlyEntityType sourceEntityType, IMutableEntityType targetEntityType) - { - if (sourceEntityType.BaseType != null) - { - targetEntityType.BaseType = targetEntityType.Model.FindEntityType(sourceEntityType.BaseType.Name); - } - - targetEntityType.SetQueryFilter(sourceEntityType.GetQueryFilter()); - targetEntityType.AddData(sourceEntityType.GetSeedData()); - targetEntityType.SetPropertyAccessMode(sourceEntityType.GetPropertyAccessMode()); - targetEntityType.SetChangeTrackingStrategy(sourceEntityType.GetChangeTrackingStrategy()); - targetEntityType.SetDiscriminatorMappingComplete(sourceEntityType.GetIsDiscriminatorMappingComplete()); - targetEntityType.SetDiscriminatorValue(sourceEntityType.GetDiscriminatorValue()); - - foreach (var property in sourceEntityType.GetDeclaredProperties()) - { - var targetProperty = property.IsShadowProperty() - ? targetEntityType.AddProperty(property.Name, property.ClrType) - : targetEntityType.AddProperty(property.Name, property.ClrType, property.GetIdentifyingMemberInfo()!); - Copy(property, targetProperty); - } - - if (sourceEntityType.BaseType == null - && sourceEntityType.GetDiscriminatorPropertyName() is string discriminatorPropertyName) - { - targetEntityType.SetDiscriminatorProperty( - targetEntityType.FindProperty(discriminatorPropertyName)!); - } - - foreach (var property in sourceEntityType.GetDeclaredComplexProperties()) - { - Copy(property, targetEntityType.AddComplexProperty( - property.Name, - property.ClrType, - property.ComplexType.ClrType, - property.ComplexType.Name, - collection: property.IsCollection)); - } - - foreach (var property in sourceEntityType.GetDeclaredServiceProperties()) - { - Copy(property, targetEntityType.AddServiceProperty( - property.GetIdentifyingMemberInfo()!, property.ClrType)); - } - - foreach (var key in sourceEntityType.GetDeclaredKeys()) - { - Copy(key, targetEntityType.AddKey( - key.Properties.Select(p => targetEntityType.FindProperty(p.Name)!).ToList())); - } - - foreach (var index in sourceEntityType.GetDeclaredIndexes()) - { - var targetProperties = index.Properties.Select(p => targetEntityType.FindProperty(p.Name)!).ToList(); - var clonedIndex = index.Name == null - ? targetEntityType.AddIndex(targetProperties) - : targetEntityType.AddIndex(targetProperties, index.Name); - Copy(index, clonedIndex); - } - - targetEntityType.AddAnnotations(sourceEntityType.GetAnnotations().Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name))); - } - - protected virtual void Copy(IReadOnlyProperty sourceProperty, IMutableProperty targetProperty) - { - if (sourceProperty.FieldInfo is FieldInfo fieldInfo) - { - targetProperty.FieldInfo = fieldInfo; - } - targetProperty.IsNullable = sourceProperty.IsNullable; - targetProperty.IsConcurrencyToken = sourceProperty.IsConcurrencyToken; - targetProperty.Sentinel = sourceProperty.Sentinel; - targetProperty.ValueGenerated = sourceProperty.ValueGenerated; - targetProperty.SetPropertyAccessMode(sourceProperty.GetPropertyAccessMode()); - targetProperty.SetBeforeSaveBehavior(sourceProperty.GetBeforeSaveBehavior()); - targetProperty.SetAfterSaveBehavior(sourceProperty.GetAfterSaveBehavior()); - targetProperty.SetMaxLength(sourceProperty.GetMaxLength()); - targetProperty.SetPrecision(sourceProperty.GetPrecision()); - targetProperty.SetScale(sourceProperty.GetScale()); - targetProperty.SetIsUnicode(sourceProperty.IsUnicode()); - targetProperty.SetProviderClrType(sourceProperty.GetProviderClrType()); - targetProperty.SetValueConverter(sourceProperty.GetValueConverter()); - targetProperty.AddAnnotations(sourceProperty.GetAnnotations().Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name))); - } - - protected virtual void Copy(IReadOnlyServiceProperty sourceProperty, IMutableServiceProperty targetProperty) - { - if (sourceProperty.FieldInfo is FieldInfo fieldInfo) - { - targetProperty.FieldInfo = fieldInfo; - } - targetProperty.SetPropertyAccessMode(sourceProperty.GetPropertyAccessMode()); - targetProperty.AddAnnotations(sourceProperty.GetAnnotations().Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name))); - } - - protected virtual void Copy(IReadOnlyComplexProperty sourceProperty, IMutableComplexProperty targetProperty) - { - if (sourceProperty.FieldInfo is FieldInfo fieldInfo) - { - targetProperty.FieldInfo = fieldInfo; - } - targetProperty.IsNullable = sourceProperty.IsNullable; - targetProperty.SetPropertyAccessMode(sourceProperty.GetPropertyAccessMode()); - targetProperty.AddAnnotations(sourceProperty.GetAnnotations().Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name))); - Copy(sourceProperty.ComplexType, targetProperty.ComplexType); - } - - protected virtual void Copy(IReadOnlyComplexType sourceComplexType, IMutableComplexType targetComplexType) - { - foreach (var property in sourceComplexType.GetDeclaredProperties()) - { - var targetProperty = property.IsShadowProperty() - ? targetComplexType.AddProperty(property.Name, property.ClrType) - : targetComplexType.AddProperty(property.Name, property.ClrType, property.GetIdentifyingMemberInfo()!); - Copy(property, targetProperty); - } - - foreach (var property in sourceComplexType.GetDeclaredComplexProperties()) - { - Copy(property, targetComplexType.AddComplexProperty( - property.Name, - property.ClrType, - property.ComplexType.ClrType, - property.ComplexType.Name, - collection: property.IsCollection)); - } - - targetComplexType.AddAnnotations(sourceComplexType.GetAnnotations().Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name))); - } - - protected virtual void Copy(IReadOnlyKey sourceKey, IMutableKey targetKey) - { - if (sourceKey.IsPrimaryKey()) - { - targetKey.DeclaringEntityType.SetPrimaryKey(targetKey.Properties); - } - - targetKey.AddAnnotations(sourceKey.GetAnnotations().Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name))); - } - - protected virtual void Copy(IReadOnlyIndex sourceIndex, IMutableIndex targetIndex) - { - targetIndex.IsDescending = sourceIndex.IsDescending; - targetIndex.IsUnique = sourceIndex.IsUnique; - targetIndex.AddAnnotations(sourceIndex.GetAnnotations().Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name))); - } - - protected virtual void Copy(IReadOnlyForeignKey sourceForeignKey, IMutableForeignKey targetForeignKey) - { - targetForeignKey.IsUnique = sourceForeignKey.IsUnique; - targetForeignKey.IsRequired = sourceForeignKey.IsRequired; - targetForeignKey.IsRequiredDependent = sourceForeignKey.IsRequiredDependent; - targetForeignKey.DeleteBehavior = sourceForeignKey.DeleteBehavior; - - if (sourceForeignKey.DependentToPrincipal != null) - { - var clonedNavigation = sourceForeignKey.DependentToPrincipal.IsShadowProperty() - ? targetForeignKey.SetDependentToPrincipal(sourceForeignKey.DependentToPrincipal.Name) - : targetForeignKey.SetDependentToPrincipal(sourceForeignKey.DependentToPrincipal.GetIdentifyingMemberInfo()); - Copy(sourceForeignKey.DependentToPrincipal, clonedNavigation!); - } - - if (sourceForeignKey.PrincipalToDependent != null) - { - var clonedNavigation = sourceForeignKey.PrincipalToDependent.IsShadowProperty() - ? targetForeignKey.SetPrincipalToDependent(sourceForeignKey.PrincipalToDependent.Name) - : targetForeignKey.SetPrincipalToDependent(sourceForeignKey.PrincipalToDependent.GetIdentifyingMemberInfo()); - Copy(sourceForeignKey.PrincipalToDependent, clonedNavigation!); - } - - targetForeignKey.AddAnnotations(sourceForeignKey.GetAnnotations() - .Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name))); - } - - protected virtual void Copy(IReadOnlyNavigation sourceNavigation, IMutableNavigation targetNavigation) - { - if (sourceNavigation.FieldInfo is FieldInfo fieldInfo) - { - targetNavigation.FieldInfo = fieldInfo; - } - - targetNavigation.SetPropertyAccessMode(sourceNavigation.GetPropertyAccessMode()); - targetNavigation.SetIsEagerLoaded(sourceNavigation.IsEagerLoaded); - targetNavigation.SetLazyLoadingEnabled(sourceNavigation.LazyLoadingEnabled); - targetNavigation.AddAnnotations(sourceNavigation.GetAnnotations() - .Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name))); - } - - protected virtual void Copy(IReadOnlySkipNavigation sourceNavigation, IMutableSkipNavigation targetNavigation) - { - if (sourceNavigation.FieldInfo is FieldInfo fieldInfo) - { - targetNavigation.FieldInfo = fieldInfo; - } - - targetNavigation.SetPropertyAccessMode(sourceNavigation.GetPropertyAccessMode()); - targetNavigation.SetIsEagerLoaded(sourceNavigation.IsEagerLoaded); - targetNavigation.SetLazyLoadingEnabled(sourceNavigation.LazyLoadingEnabled); - targetNavigation.AddAnnotations(sourceNavigation.GetAnnotations().Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name))); - if (sourceNavigation.ForeignKey != null) - { - var targetDependentType = targetNavigation.DeclaringEntityType.Model.FindEntityType( - sourceNavigation.ForeignKey.DeclaringEntityType.Name)!; - var targetPrincipalType = targetNavigation.DeclaringEntityType.Model.FindEntityType( - sourceNavigation.ForeignKey.PrincipalEntityType.Name)!; - var targetKey = targetPrincipalType.FindKey( - sourceNavigation.ForeignKey.PrincipalKey.Properties.Select(p => targetPrincipalType.FindProperty(p.Name)!).ToList())!; - var targetForeignKey = targetDependentType.FindForeignKey( - sourceNavigation.ForeignKey.Properties.Select(p => targetDependentType.FindProperty(p.Name)!).ToList(), - targetKey, - targetPrincipalType)!; - targetNavigation.SetForeignKey(targetForeignKey); - } - - if (sourceNavigation.Inverse != null) - { - var targetEntityType = targetNavigation.DeclaringEntityType.Model.FindEntityType( - sourceNavigation.Inverse.DeclaringEntityType.Name)!; - targetNavigation.SetInverse( - targetEntityType.FindSkipNavigation(sourceNavigation.Inverse.Name)); - } - } + public abstract TestHelpers TestHelpers { get; } + public virtual DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder) => builder; + public virtual IServiceCollection AddServices(IServiceCollection services) => services; } public abstract class TestModelBuilder : IInfrastructure { - protected TestModelBuilder(TestHelpers testHelpers, Action? configure) + protected TestModelBuilder(ModelBuilderFixtureBase fixture, Action? configure) { + var testHelpers = fixture.TestHelpers; var options = new LoggingOptions(); options.Initialize(new DbContextOptionsBuilder().EnableSensitiveDataLogging(false).Options); ValidationLoggerFactory = new ListLoggerFactory(l => l == DbLoggerCategory.Model.Validation.Name); @@ -1091,7 +81,9 @@ protected TestModelBuilder(TestHelpers testHelpers, Action Initialize( Action onModelCreating = null, Action onConfiguring = null, - Action addServices = null, + Func addServices = null, Action seed = null, Func shouldLogCategory = null, Func createTestStore = null, @@ -58,7 +58,7 @@ protected virtual ContextFactory Initialize( protected virtual Task> InitializeAsync( Action onModelCreating = null, Action onConfiguring = null, - Action addServices = null, + Func addServices = null, Action seed = null, Func shouldLogCategory = null, Func createTestStore = null, @@ -78,7 +78,7 @@ protected virtual Task> InitializeAsync( protected ContextFactory CreateContextFactory( Action onModelCreating = null, Action onConfiguring = null, - Action addServices = null, + Func addServices = null, Func shouldLogCategory = null, Func createTestStore = null, bool usePooling = true) diff --git a/test/EFCore.Specification.Tests/Scaffolding/CompiledModelTestBase.cs b/test/EFCore.Specification.Tests/Scaffolding/CompiledModelTestBase.cs index e578bff2f08..38beabae27c 100644 --- a/test/EFCore.Specification.Tests/Scaffolding/CompiledModelTestBase.cs +++ b/test/EFCore.Specification.Tests/Scaffolding/CompiledModelTestBase.cs @@ -1241,8 +1241,8 @@ protected virtual void Test( Action? useContext = null, Action? onConfiguring = null, CompiledModelCodeGenerationOptions? options = null, - Action? addServices = null, - Action? addDesignTimeServices = null, + Func? addServices = null, + Func? addDesignTimeServices = null, string? expectedExceptionMessage = null, [CallerMemberName] string testName = "") => Test( @@ -1262,8 +1262,8 @@ protected virtual (TContext?, IModel?) Test( Action? useContext = null, Action? onConfiguring = null, CompiledModelCodeGenerationOptions? options = null, - Action? addServices = null, - Action? addDesignTimeServices = null, + Func? addServices = null, + Func? addDesignTimeServices = null, string? expectedExceptionMessage = null, [CallerMemberName] string testName = "") where TContext : DbContext @@ -1313,7 +1313,7 @@ protected virtual (TContext?, IModel?) Test( var compiledModel = CompileModel(scaffoldedFiles, options, context); assertModel?.Invoke(compiledModel); - //TODO: Assert model equality + TestHelpers.ModelAsserter.AssertEqual(context.Model, compiledModel); if (useContext != null) { diff --git a/test/EFCore.Specification.Tests/TestUtilities/ModelAsserter.cs b/test/EFCore.Specification.Tests/TestUtilities/ModelAsserter.cs new file mode 100644 index 00000000000..8852de4018a --- /dev/null +++ b/test/EFCore.Specification.Tests/TestUtilities/ModelAsserter.cs @@ -0,0 +1,1117 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.EntityFrameworkCore.Metadata.Internal; + +#nullable enable + +namespace Microsoft.EntityFrameworkCore.TestUtilities; + +public class ModelAsserter +{ + protected ModelAsserter() + { + } + + public static ModelAsserter Instance { get; } = new(); + + public virtual void AssertEqual( + IReadOnlyModel expected, + IReadOnlyModel actual, + bool compareAnnotations = true) + => AssertEqual( + expected, + actual, + compareAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations: compareAnnotations); + + public virtual void AssertEqual( + IReadOnlyModel expected, + IReadOnlyModel actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareMemberAnnotations) + { + expectedAnnotations = expectedAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); + actualAnnotations = actualAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); + + var designTime = expected is Model && actual is Model; + + Assert.Multiple( + () => Assert.Equal(expected.ModelId, actual.ModelId), + () => Assert.Equal(expected.GetProductVersion(), actual.GetProductVersion()), + () => + { + if (designTime) + { + Assert.Equal(expected.GetProductVersion(), actual.GetProductVersion()); + } + }, + () => + { + if (designTime) + { + Assert.Equal(expected.GetPropertyAccessMode(), actual.GetPropertyAccessMode()); + } + }, + () => AssertEqual(expected.GetEntityTypes(), actual.GetEntityTypes(), + assertOrder: true, compareAnnotations: compareMemberAnnotations), + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + } + + public virtual void AssertEqual( + IEnumerable expectedEntityTypes, + IEnumerable actualEntityTypes, + bool assertOrder = false, + bool compareAnnotations = false) + { + if (!assertOrder) + { + expectedEntityTypes = expectedEntityTypes.OrderBy(p => p.Name); + actualEntityTypes = actualEntityTypes.OrderBy(p => p.Name); + } + + Assert.Equal(expectedEntityTypes, actualEntityTypes, + (expected, actual) => + AssertEqual( + expected, + actual, + compareAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareBackreferences: false, + compareMemberAnnotations: compareAnnotations)); + } + + public virtual bool AssertEqual(IReadOnlyEntityType? expected, IReadOnlyEntityType? actual, + IEnumerable expectedAnnotations, IEnumerable actualAnnotations, + bool compareBackreferences = false, bool compareMemberAnnotations = false) + { + if (expected == null) + { + Assert.Null(actual); + + return true; + } + + Assert.NotNull(actual); + + expectedAnnotations = expectedAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); + actualAnnotations = actualAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); + + var designTime = expected is EntityType && actual is EntityType; + + Assert.Multiple( + () => Assert.Equal(expected.Name, actual.Name), + () => Assert.Equal(expected.ClrType, actual.ClrType), + () => Assert.Equal(expected.HasSharedClrType, actual.HasSharedClrType), + () => Assert.Equal(expected.IsPropertyBag, actual.IsPropertyBag), + () => Assert.Equal(expected.GetQueryFilter(), actual.GetQueryFilter()), + () => + { + if (designTime) + { + Assert.Equal(expected.GetNavigationAccessMode(), actual.GetNavigationAccessMode()); + } + }, + () => + { + if (designTime) + { + Assert.Equal(expected.GetPropertyAccessMode(), actual.GetPropertyAccessMode()); + } + }, + () => + { + if (designTime) + { + Assert.Equal(expected.GetSeedData(), actual.GetSeedData()); + } + }, + () => Assert.Equal(expected.GetChangeTrackingStrategy(), actual.GetChangeTrackingStrategy()), + () => Assert.Equal(expected.GetDiscriminatorPropertyName(), actual.GetDiscriminatorPropertyName()), + () => Assert.Equal(expected.GetDiscriminatorValue(), actual.GetDiscriminatorValue()), + () => Assert.Equal(expected.GetIsDiscriminatorMappingComplete(), actual.GetIsDiscriminatorMappingComplete()), + () => AssertEqual(expected.GetProperties(), actual.GetProperties(), + assertOrder: true, compareAnnotations: compareMemberAnnotations), + () => AssertEqual(expected.GetServiceProperties(), actual.GetServiceProperties(), + assertOrder: true, compareAnnotations: compareMemberAnnotations), + () => AssertEqual(expected.GetSkipNavigations(), actual.GetSkipNavigations(), + assertOrder: true, compareAnnotations: compareMemberAnnotations), + () => AssertEqual(expected.GetForeignKeys(), actual.GetForeignKeys(), + assertOrder: true, compareAnnotations: compareMemberAnnotations), + () => AssertEqual(expected.GetKeys(), actual.GetKeys(), + assertOrder: true, compareAnnotations: compareMemberAnnotations), + () => AssertEqual(expected.GetIndexes(), actual.GetIndexes(), + assertOrder: true, compareAnnotations: compareMemberAnnotations), + () => AssertEqual(expected.GetComplexProperties(), actual.GetComplexProperties(), + assertOrder: true, compareAnnotations: compareMemberAnnotations), + () => + { + if (compareBackreferences) + { + Assert.Equal(expected.BaseType?.Name, actual.BaseType?.Name); + } + }, + () => + { + if (compareBackreferences) + { + Assert.Equal(expected.GetReferencingForeignKeys(), actual.GetReferencingForeignKeys()); + } + }, + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + + return true; + } + + public virtual bool AssertEqual(IReadOnlyComplexType expected, IReadOnlyComplexType actual, + IEnumerable expectedAnnotations, IEnumerable actualAnnotations, + bool compareBackreferences = false, + bool compareMemberAnnotations = false) + { + expectedAnnotations = expectedAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); + actualAnnotations = actualAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); + + var designTime = expected is ComplexType && actual is ComplexType; + + Assert.Multiple( + () => Assert.Equal(expected.Name, actual.Name), + () => Assert.Equal(expected.ClrType, actual.ClrType), + () => + { + if (designTime) + { + Assert.Equal(expected.GetPropertyAccessMode(), actual.GetPropertyAccessMode()); + } + }, + () => Assert.Equal(expected.GetChangeTrackingStrategy(), actual.GetChangeTrackingStrategy()), + () => AssertEqual(expected.GetProperties(), actual.GetProperties(), + assertOrder: true, compareAnnotations: compareMemberAnnotations), + () => AssertEqual(expected.GetComplexProperties(), actual.GetComplexProperties(), + assertOrder: true, compareAnnotations: compareMemberAnnotations), + () => + { + if (compareBackreferences) + { + Assert.Equal(expected.ContainingEntityType.Name, actual.ContainingEntityType.Name); + } + }, + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + + return true; + } + + public virtual void AssertEqual( + IEnumerable expectedProperties, + IEnumerable actualProperties, + bool assertOrder = false, + bool compareAnnotations = false) + { + if (!assertOrder) + { + expectedProperties = expectedProperties.OrderBy(p => p.Name); + actualProperties = actualProperties.OrderBy(p => p.Name); + } + + Assert.Equal(expectedProperties, actualProperties, + (expected, actual) => + AssertEqual( + expected, + actual, + compareAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareBackreferences: false, + compareMemberAnnotations: compareAnnotations)); + } + + public virtual bool AssertEqual(IReadOnlyComplexProperty? expected, IReadOnlyComplexProperty? actual, + IEnumerable expectedAnnotations, IEnumerable actualAnnotations, + bool compareBackreferences = false, + bool compareMemberAnnotations = false) + { + if (expected == null) + { + Assert.Null(actual); + + return true; + } + + Assert.NotNull(actual); + + expectedAnnotations = expectedAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); + actualAnnotations = actualAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); + + Assert.Multiple( + () => Assert.Equal(expected.Name, actual.Name), + () => Assert.Equal(expected.ClrType, actual.ClrType), + () => Assert.Equal(expected.FieldInfo, actual.FieldInfo), + () => Assert.Equal(expected.GetIdentifyingMemberInfo(), actual.GetIdentifyingMemberInfo()), + () => Assert.Equal(expected.IsShadowProperty(), actual.IsShadowProperty()), + () => Assert.Equal(expected.IsNullable, actual.IsNullable), + () => Assert.Equal(expected.Sentinel, actual.Sentinel), + () => Assert.Equal(expected.GetPropertyAccessMode(), actual.GetPropertyAccessMode()), + () => AssertEqual(expected.ComplexType, actual.ComplexType, + compareMemberAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareMemberAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareBackreferences: false, + compareMemberAnnotations: compareMemberAnnotations), + () => + { + if (compareBackreferences) + { + Assert.Equal(expected.DeclaringType.Name, actual.DeclaringType.Name); + } + }, + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + + return true; + } + + public virtual void AssertEqual( + IEnumerable expectedProperties, + IEnumerable actualProperties, + bool assertOrder = false, + bool compareAnnotations = false) + { + if (!assertOrder) + { + expectedProperties = expectedProperties.OrderBy(p => p.Name); + actualProperties = actualProperties.OrderBy(p => p.Name); + } + + Assert.Equal(expectedProperties, actualProperties, + (expected, actual) => + AssertEqual( + expected, + actual, + compareAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareBackreferences: false, + compareAnnotations)); + } + + public virtual bool AssertEqual( + IReadOnlyProperty? expected, + IReadOnlyProperty? actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareBackreferences = false, + bool compareMemberAnnotations = false) + { + if (expected == null) + { + Assert.Null(actual); + + return true; + } + + Assert.NotNull(actual); + + expectedAnnotations = expectedAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); + actualAnnotations = actualAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); + + Assert.Multiple( + () => Assert.Equal(expected.Name, actual.Name), + () => Assert.Equal(expected.ClrType, actual.ClrType), + () => Assert.Equal(expected.FieldInfo?.Name, actual.FieldInfo?.Name), + () => Assert.Equal(expected.GetIdentifyingMemberInfo()?.Name, actual.GetIdentifyingMemberInfo()?.Name), + () => Assert.Equal(expected.IsShadowProperty(), actual.IsShadowProperty()), + () => Assert.Equal(expected.IsNullable, actual.IsNullable), + () => Assert.Equal(expected.IsConcurrencyToken, actual.IsConcurrencyToken), + () => Assert.Equal(expected.Sentinel, actual.Sentinel), + () => Assert.Equal(expected.ValueGenerated, actual.ValueGenerated), + () => Assert.Equal(expected.GetPropertyAccessMode(), actual.GetPropertyAccessMode()), + () => Assert.Equal(expected.GetBeforeSaveBehavior(), actual.GetBeforeSaveBehavior()), + () => Assert.Equal(expected.GetAfterSaveBehavior(), actual.GetAfterSaveBehavior()), + () => + { + if (actual.Name != (actual.DeclaringType as IEntityType)?.GetDiscriminatorPropertyName()) + { + Assert.Equal(expected.GetMaxLength(), actual.GetMaxLength()); + } + }, + () => Assert.Equal(expected.GetPrecision(), actual.GetPrecision()), + () => Assert.Equal(expected.GetScale(), actual.GetScale()), + () => Assert.Equal(expected.IsUnicode(), actual.IsUnicode()), + () => Assert.Equal(expected.GetProviderClrType(), actual.GetProviderClrType()), + () => + { + var actualConverter = actual.GetValueConverter() ?? actual.FindTypeMapping()?.Converter; + if ((expected.GetValueConverter() ?? expected.FindTypeMapping()?.Converter) == null) + { + Assert.Null(actualConverter); + } + else + { + Assert.NotNull(actualConverter); + } + }, + () => + { + var actualComparer = actual.GetValueComparer() ?? actual.FindTypeMapping()?.Comparer; + if ((expected.GetValueComparer() ?? expected.FindTypeMapping()?.Comparer) == null) + { + Assert.Null(actualComparer); + } + else + { + Assert.NotNull(actualComparer); + } + }, + () => Assert.Equal(expected.IsKey(), actual.IsKey()), + () => Assert.Equal(expected.IsForeignKey(), actual.IsForeignKey()), + () => Assert.Equal(expected.IsIndex(), actual.IsIndex()), + () => + { + if (compareBackreferences) + { + Assert.Equal(expected.DeclaringType.Name, actual.DeclaringType.Name); + } + }, + () => + { + if (compareBackreferences) + { + Assert.Equal(expected.GetContainingForeignKeys(), actual.GetContainingForeignKeys(), ForeignKeyComparer.Instance); + } + }, + () => + { + if (compareBackreferences) + { + Assert.Equal(expected.GetContainingIndexes(), actual.GetContainingIndexes(), IndexComparer.Instance); + } + }, + () => + { + if (compareBackreferences) + { + Assert.Equal(expected.GetContainingKeys(), actual.GetContainingKeys(), KeyComparer.Instance); + } + }, + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + + return true; + } + + public virtual void AssertEqual( + IEnumerable expectedProperties, + IEnumerable actualProperties, + bool assertOrder = false, + bool compareAnnotations = false) + { + if (!assertOrder) + { + expectedProperties = expectedProperties.OrderBy(p => p.Name); + actualProperties = actualProperties.OrderBy(p => p.Name); + } + + Assert.Equal(expectedProperties, actualProperties, + (expected, actual) => + AssertEqual( + expected, + actual, + compareAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareBackreferences: false)); + } + + public virtual bool AssertEqual(IReadOnlyServiceProperty? expected, IReadOnlyServiceProperty? actual, + IEnumerable expectedAnnotations, IEnumerable actualAnnotations, + bool compareBackreferences = false) + { + if (expected == null) + { + Assert.Null(actual); + + return true; + } + + Assert.NotNull(actual); + + expectedAnnotations = expectedAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); + actualAnnotations = actualAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); + + Assert.Multiple( + () => Assert.Equal(expected.Name, actual.Name), + () => Assert.Equal(expected.ClrType, actual.ClrType), + () => Assert.Equal(expected.FieldInfo, actual.FieldInfo), + () => Assert.Equal(expected.GetIdentifyingMemberInfo(), actual.GetIdentifyingMemberInfo()), + () => Assert.Equal(expected.IsShadowProperty(), actual.IsShadowProperty()), + () => Assert.Equal(expected.Sentinel, actual.Sentinel), + () => Assert.Equal(expected.GetPropertyAccessMode(), actual.GetPropertyAccessMode()), + () => + { + if (compareBackreferences) + { + Assert.Equal(expected.DeclaringType.Name, actual.DeclaringType.Name); + } + }, + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + + return true; + } + + public virtual void AssertEqual( + IEnumerable expectedNavigations, + IEnumerable actualNavigations, + bool assertOrder = false, + bool compareAnnotations = false) + { + if (!assertOrder) + { + expectedNavigations = expectedNavigations.OrderBy(p => p.Name); + actualNavigations = actualNavigations.OrderBy(p => p.Name); + } + + Assert.Equal(expectedNavigations, actualNavigations, + (expected, actual) => + AssertEqual( + expected, + actual, + compareAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareBackreferences: false)); + } + + public virtual bool AssertEqual(IReadOnlyNavigation? expected, IReadOnlyNavigation? actual, + IEnumerable expectedAnnotations, IEnumerable actualAnnotations, + bool compareBackreferences = false) + { + if (expected == null) + { + Assert.Null(actual); + + return true; + } + + Assert.NotNull(actual); + + expectedAnnotations = expectedAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); + actualAnnotations = actualAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); + + Assert.Multiple( + () => Assert.Equal(expected.Name, actual.Name), + () => Assert.Equal(expected.ClrType, actual.ClrType), + () => Assert.Equal(expected.FieldInfo, actual.FieldInfo), + () => Assert.Equal(expected.GetIdentifyingMemberInfo(), actual.GetIdentifyingMemberInfo()), + () => Assert.Equal(expected.IsShadowProperty(), actual.IsShadowProperty()), + () => Assert.Equal(expected.IsCollection, actual.IsCollection), + () => Assert.Equal(expected.IsEagerLoaded, actual.IsEagerLoaded), + () => Assert.Equal(expected.LazyLoadingEnabled, actual.LazyLoadingEnabled), + () => Assert.Equal(expected.Sentinel, actual.Sentinel), + () => Assert.Equal(expected.GetPropertyAccessMode(), actual.GetPropertyAccessMode()), + () => + { + if (compareBackreferences) + { + Assert.Equal(expected.DeclaringType.Name, actual.DeclaringType.Name); + } + }, + () => + { + if (compareBackreferences) + { + Assert.Equal(expected.ForeignKey, actual.ForeignKey, ForeignKeyComparer.Instance); + } + }, + () => + { + if (compareBackreferences) + { + Assert.Equal(expected.Inverse?.Name, actual.Inverse?.Name); + } + }, + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + + return true; + } + + public virtual void AssertEqual( + IEnumerable expectedNavigations, + IEnumerable actualNavigations, + bool assertOrder = false, + bool compareAnnotations = false) + { + if (!assertOrder) + { + expectedNavigations = expectedNavigations.OrderBy(p => p.Name); + actualNavigations = actualNavigations.OrderBy(p => p.Name); + } + + Assert.Equal(expectedNavigations, actualNavigations, + (expected, actual) => + AssertEqual( + expected, + actual, + compareAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareBackreferences: false)); + } + + public virtual bool AssertEqual(IReadOnlySkipNavigation expected, IReadOnlySkipNavigation actual, + IEnumerable expectedAnnotations, IEnumerable actualAnnotations, + bool compareBackreferences = false) + { + if (expected == null) + { + Assert.Null(actual); + + return true; + } + + Assert.NotNull(actual); + + expectedAnnotations = expectedAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); + actualAnnotations = actualAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); + + Assert.Multiple( + () => Assert.Equal(expected.Name, actual.Name), + () => Assert.Equal(expected.ClrType, actual.ClrType), + () => Assert.Equal(expected.FieldInfo, actual.FieldInfo), + () => Assert.Equal(expected.GetIdentifyingMemberInfo(), actual.GetIdentifyingMemberInfo()), + () => Assert.Equal(expected.IsShadowProperty(), actual.IsShadowProperty()), + () => Assert.Equal(expected.IsCollection, actual.IsCollection), + () => Assert.Equal(expected.IsEagerLoaded, actual.IsEagerLoaded), + () => Assert.Equal(expected.LazyLoadingEnabled, actual.LazyLoadingEnabled), + () => Assert.Equal(expected.Sentinel, actual.Sentinel), + () => Assert.Equal(expected.GetPropertyAccessMode(), actual.GetPropertyAccessMode()), + () => + { + if (compareBackreferences) + { + Assert.Equal(expected.DeclaringType.Name, actual.DeclaringType.Name); + } + }, + () => + { + if (compareBackreferences) + { + Assert.Equal(expected.ForeignKey!, actual.ForeignKey!, ForeignKeyComparer.Instance); + } + }, + () => + { + if (compareBackreferences) + { + Assert.Equal(expected.Inverse?.Name, actual.Inverse?.Name); + } + }, + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + + return true; + } + + public virtual void AssertEqual( + IEnumerable expectedKeys, + IEnumerable actualKeys, + bool assertOrder = false, + bool compareAnnotations = false) + { + if (!assertOrder) + { + expectedKeys = expectedKeys.Order(KeyComparer.Instance); + actualKeys = actualKeys.Order(KeyComparer.Instance); + } + + Assert.Equal(expectedKeys, actualKeys, + (expected, actual) => + AssertEqual( + expected, + actual, + compareAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareBackreferences: false)); + } + + public virtual bool AssertEqual( + IReadOnlyKey expected, + IReadOnlyKey actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareBackreferences = false, + bool compareMemberAnnotations = false) + { + if (expected == null) + { + Assert.Null(actual); + + return true; + } + + Assert.NotNull(actual); + + expectedAnnotations = expectedAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); + actualAnnotations = actualAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); + + Assert.Multiple( + () => + { + if (compareBackreferences) + { + Assert.Equal(expected, actual, KeyComparer.Instance); + } + else + { + Assert.Equal(expected.Properties, actual.Properties, PropertyListComparer.Instance); + } + }, + () => Assert.Equal(expected.IsPrimaryKey(), actual.IsPrimaryKey()), + () => + { + if (compareBackreferences) + { + Assert.Equal(expected.DeclaringEntityType.Name, actual.DeclaringEntityType.Name); + } + }, + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + + return true; + } + + public virtual void AssertEqual( + IEnumerable expectedForeignKey, + IEnumerable actualForeignKey, + bool assertOrder = false, + bool compareAnnotations = false) + { + if (!assertOrder) + { + expectedForeignKey = expectedForeignKey.Order(ForeignKeyComparer.Instance); + actualForeignKey = actualForeignKey.Order(ForeignKeyComparer.Instance); + } + + Assert.Equal(expectedForeignKey, actualForeignKey, + (expected, actual) => + AssertEqual( + expected, + actual, + compareAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareBackreferences: false, + compareMemberAnnotations: compareAnnotations)); + } + + public virtual bool AssertEqual( + IReadOnlyForeignKey expected, + IReadOnlyForeignKey actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareBackreferences = false, + bool compareMemberAnnotations = false) + { + if (expected == null) + { + Assert.Null(actual); + + return true; + } + + Assert.NotNull(actual); + + expectedAnnotations = expectedAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); + actualAnnotations = actualAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); + + Assert.Multiple( + () => + { + if (compareBackreferences) + { + Assert.Equal(expected, actual, ForeignKeyComparer.Instance); + } + else + { + Assert.Equal(expected.Properties, actual.Properties, PropertyListComparer.Instance); + Assert.Equal(expected.PrincipalKey.Properties, actual.PrincipalKey.Properties, PropertyListComparer.Instance); + } + }, + () => Assert.Equal(expected.IsRequired, actual.IsRequired), + () => Assert.Equal(expected.IsRequiredDependent, actual.IsRequiredDependent), + () => Assert.Equal(expected.IsUnique, actual.IsUnique), + () => Assert.Equal(expected.DeleteBehavior, actual.DeleteBehavior), + () => AssertEqual(expected.DependentToPrincipal, actual.DependentToPrincipal, + compareMemberAnnotations + ? expected.DependentToPrincipal?.GetAnnotations() ?? Enumerable.Empty() + : Enumerable.Empty(), + compareMemberAnnotations + ? actual.DependentToPrincipal?.GetAnnotations() ?? Enumerable.Empty() + : Enumerable.Empty(), + compareBackreferences: true), + () => AssertEqual(expected.PrincipalToDependent, actual.PrincipalToDependent, + compareMemberAnnotations + ? expected.PrincipalToDependent?.GetAnnotations() ?? Enumerable.Empty() + : Enumerable.Empty(), + compareMemberAnnotations + ? actual.PrincipalToDependent?.GetAnnotations() ?? Enumerable.Empty() + : Enumerable.Empty(), + compareBackreferences: true), + () => + { + if (compareBackreferences) + { + Assert.Equal(expected.DeclaringEntityType.Name, actual.DeclaringEntityType.Name); + } + }, + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + + return true; + } + + public virtual void AssertEqual( + IEnumerable expectedIndex, + IEnumerable actualIndex, + bool assertOrder = false, + bool compareAnnotations = false) + { + if (!assertOrder) + { + expectedIndex = expectedIndex.Order(IndexComparer.Instance); + actualIndex = actualIndex.Order(IndexComparer.Instance); + } + + Assert.Equal(expectedIndex, actualIndex, + (expected, actual) => + AssertEqual( + expected, + actual, + compareAnnotations ? expected.GetAnnotations() : Enumerable.Empty(), + compareAnnotations ? actual.GetAnnotations() : Enumerable.Empty(), + compareBackreferences: false)); + } + + public virtual bool AssertEqual( + IReadOnlyIndex expected, + IReadOnlyIndex actual, + IEnumerable expectedAnnotations, + IEnumerable actualAnnotations, + bool compareBackreferences = false, + bool compareMemberAnnotations = false) + { + if (expected == null) + { + Assert.Null(actual); + + return true; + } + + Assert.NotNull(actual); + + expectedAnnotations = expectedAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); + actualAnnotations = actualAnnotations.Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name)); + + var designTime = expected is Metadata.Internal.Index && actual is Metadata.Internal.Index; + + Assert.Multiple( + () => + { + if (compareBackreferences) + { + Assert.Equal(expected, actual, IndexComparer.Instance); + } + else + { + Assert.Equal(expected.Properties, actual.Properties, PropertyListComparer.Instance); + } + }, + () => + { + if (designTime) + { + Assert.Equal(expected.IsDescending, actual.IsDescending); + } + }, + () => Assert.Equal(expected.IsUnique, actual.IsUnique), + () => Assert.Equal(expected.Name, actual.Name), + () => + { + if (compareBackreferences) + { + Assert.Equal(expected.DeclaringEntityType.Name, actual.DeclaringEntityType.Name); + } + }, + () => Assert.Equal(expectedAnnotations, actualAnnotations, TestAnnotationComparer.Instance)); + + return true; + } + + public virtual IReadOnlyModel Clone(IReadOnlyModel model) + { + IMutableModel modelClone = new Model(model.ModelId); + modelClone.SetChangeTrackingStrategy(model.GetChangeTrackingStrategy()); + + if (model.GetProductVersion() is string productVersion) + { + modelClone.SetProductVersion(productVersion); + } + + modelClone.SetPropertyAccessMode(model.GetPropertyAccessMode()); + modelClone.AddAnnotations(model.GetAnnotations().Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name))); + + var clonedEntityTypes = new Dictionary(); + foreach (var entityType in ((IModel)model).GetEntityTypesInHierarchicalOrder()) + { + var clonedEntityType = entityType.HasSharedClrType + ? modelClone.AddEntityType(entityType.Name, entityType.ClrType) + : modelClone.AddEntityType(entityType.ClrType); + + Copy(entityType, clonedEntityType); + clonedEntityTypes.Add(entityType, clonedEntityType); + } + + foreach (var clonedEntityType in clonedEntityTypes) + { + var targetEntityType = clonedEntityType.Value; + foreach (var foreignKey in clonedEntityType.Key.GetDeclaredForeignKeys()) + { + var targetPrincipalEntityType = targetEntityType.Model.FindEntityType(foreignKey.PrincipalEntityType.Name)!; + var clonedForeignKey = targetEntityType.AddForeignKey( + foreignKey.Properties.Select(p => targetEntityType.FindProperty(p.Name)!).ToList(), + targetPrincipalEntityType.FindKey( + foreignKey.PrincipalKey.Properties.Select(p => targetPrincipalEntityType.FindProperty(p.Name)!).ToList())!, + targetPrincipalEntityType); + Copy(foreignKey, clonedForeignKey); + } + } + + foreach (var clonedEntityType in clonedEntityTypes) + { + foreach (var skipNavigation in clonedEntityType.Key.GetDeclaredSkipNavigations()) + { + var targetEntityType = clonedEntityType.Value; + var otherEntityType = targetEntityType.Model.FindEntityType(skipNavigation.TargetEntityType.Name)!; + Copy(skipNavigation, clonedEntityType.Value.AddSkipNavigation( + skipNavigation.Name, + skipNavigation.GetIdentifyingMemberInfo(), + otherEntityType, + skipNavigation.IsCollection, + skipNavigation.IsOnDependent)); + } + } + + return modelClone; + } + + protected virtual void Copy(IReadOnlyEntityType sourceEntityType, IMutableEntityType targetEntityType) + { + if (sourceEntityType.BaseType != null) + { + targetEntityType.BaseType = targetEntityType.Model.FindEntityType(sourceEntityType.BaseType.Name); + } + + targetEntityType.SetQueryFilter(sourceEntityType.GetQueryFilter()); + targetEntityType.AddData(sourceEntityType.GetSeedData()); + targetEntityType.SetPropertyAccessMode(sourceEntityType.GetPropertyAccessMode()); + targetEntityType.SetChangeTrackingStrategy(sourceEntityType.GetChangeTrackingStrategy()); + targetEntityType.SetDiscriminatorMappingComplete(sourceEntityType.GetIsDiscriminatorMappingComplete()); + targetEntityType.SetDiscriminatorValue(sourceEntityType.GetDiscriminatorValue()); + + foreach (var property in sourceEntityType.GetDeclaredProperties()) + { + var targetProperty = property.IsShadowProperty() + ? targetEntityType.AddProperty(property.Name, property.ClrType) + : targetEntityType.AddProperty(property.Name, property.ClrType, property.GetIdentifyingMemberInfo()!); + Copy(property, targetProperty); + } + + if (sourceEntityType.BaseType == null + && sourceEntityType.GetDiscriminatorPropertyName() is string discriminatorPropertyName) + { + targetEntityType.SetDiscriminatorProperty( + targetEntityType.FindProperty(discriminatorPropertyName)!); + } + + foreach (var property in sourceEntityType.GetDeclaredComplexProperties()) + { + Copy(property, targetEntityType.AddComplexProperty( + property.Name, + property.ClrType, + property.ComplexType.ClrType, + property.ComplexType.Name, + collection: property.IsCollection)); + } + + foreach (var property in sourceEntityType.GetDeclaredServiceProperties()) + { + Copy(property, targetEntityType.AddServiceProperty( + property.GetIdentifyingMemberInfo()!, property.ClrType)); + } + + foreach (var key in sourceEntityType.GetDeclaredKeys()) + { + Copy(key, targetEntityType.AddKey( + key.Properties.Select(p => targetEntityType.FindProperty(p.Name)!).ToList())); + } + + foreach (var index in sourceEntityType.GetDeclaredIndexes()) + { + var targetProperties = index.Properties.Select(p => targetEntityType.FindProperty(p.Name)!).ToList(); + var clonedIndex = index.Name == null + ? targetEntityType.AddIndex(targetProperties) + : targetEntityType.AddIndex(targetProperties, index.Name); + Copy(index, clonedIndex); + } + + targetEntityType.AddAnnotations(sourceEntityType.GetAnnotations().Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name))); + } + + protected virtual void Copy(IReadOnlyProperty sourceProperty, IMutableProperty targetProperty) + { + if (sourceProperty.FieldInfo is FieldInfo fieldInfo) + { + targetProperty.FieldInfo = fieldInfo; + } + targetProperty.IsNullable = sourceProperty.IsNullable; + targetProperty.IsConcurrencyToken = sourceProperty.IsConcurrencyToken; + targetProperty.Sentinel = sourceProperty.Sentinel; + targetProperty.ValueGenerated = sourceProperty.ValueGenerated; + targetProperty.SetPropertyAccessMode(sourceProperty.GetPropertyAccessMode()); + targetProperty.SetBeforeSaveBehavior(sourceProperty.GetBeforeSaveBehavior()); + targetProperty.SetAfterSaveBehavior(sourceProperty.GetAfterSaveBehavior()); + targetProperty.SetMaxLength(sourceProperty.GetMaxLength()); + targetProperty.SetPrecision(sourceProperty.GetPrecision()); + targetProperty.SetScale(sourceProperty.GetScale()); + targetProperty.SetIsUnicode(sourceProperty.IsUnicode()); + targetProperty.SetProviderClrType(sourceProperty.GetProviderClrType()); + targetProperty.SetValueConverter(sourceProperty.GetValueConverter()); + targetProperty.AddAnnotations(sourceProperty.GetAnnotations().Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name))); + } + + protected virtual void Copy(IReadOnlyServiceProperty sourceProperty, IMutableServiceProperty targetProperty) + { + if (sourceProperty.FieldInfo is FieldInfo fieldInfo) + { + targetProperty.FieldInfo = fieldInfo; + } + targetProperty.SetPropertyAccessMode(sourceProperty.GetPropertyAccessMode()); + targetProperty.AddAnnotations(sourceProperty.GetAnnotations().Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name))); + } + + protected virtual void Copy(IReadOnlyComplexProperty sourceProperty, IMutableComplexProperty targetProperty) + { + if (sourceProperty.FieldInfo is FieldInfo fieldInfo) + { + targetProperty.FieldInfo = fieldInfo; + } + targetProperty.IsNullable = sourceProperty.IsNullable; + targetProperty.SetPropertyAccessMode(sourceProperty.GetPropertyAccessMode()); + targetProperty.AddAnnotations(sourceProperty.GetAnnotations().Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name))); + Copy(sourceProperty.ComplexType, targetProperty.ComplexType); + } + + protected virtual void Copy(IReadOnlyComplexType sourceComplexType, IMutableComplexType targetComplexType) + { + foreach (var property in sourceComplexType.GetDeclaredProperties()) + { + var targetProperty = property.IsShadowProperty() + ? targetComplexType.AddProperty(property.Name, property.ClrType) + : targetComplexType.AddProperty(property.Name, property.ClrType, property.GetIdentifyingMemberInfo()!); + Copy(property, targetProperty); + } + + foreach (var property in sourceComplexType.GetDeclaredComplexProperties()) + { + Copy(property, targetComplexType.AddComplexProperty( + property.Name, + property.ClrType, + property.ComplexType.ClrType, + property.ComplexType.Name, + collection: property.IsCollection)); + } + + targetComplexType.AddAnnotations(sourceComplexType.GetAnnotations().Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name))); + } + + protected virtual void Copy(IReadOnlyKey sourceKey, IMutableKey targetKey) + { + if (sourceKey.IsPrimaryKey()) + { + targetKey.DeclaringEntityType.SetPrimaryKey(targetKey.Properties); + } + + targetKey.AddAnnotations(sourceKey.GetAnnotations().Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name))); + } + + protected virtual void Copy(IReadOnlyIndex sourceIndex, IMutableIndex targetIndex) + { + targetIndex.IsDescending = sourceIndex.IsDescending; + targetIndex.IsUnique = sourceIndex.IsUnique; + targetIndex.AddAnnotations(sourceIndex.GetAnnotations().Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name))); + } + + protected virtual void Copy(IReadOnlyForeignKey sourceForeignKey, IMutableForeignKey targetForeignKey) + { + targetForeignKey.IsUnique = sourceForeignKey.IsUnique; + targetForeignKey.IsRequired = sourceForeignKey.IsRequired; + targetForeignKey.IsRequiredDependent = sourceForeignKey.IsRequiredDependent; + targetForeignKey.DeleteBehavior = sourceForeignKey.DeleteBehavior; + + if (sourceForeignKey.DependentToPrincipal != null) + { + var clonedNavigation = sourceForeignKey.DependentToPrincipal.IsShadowProperty() + ? targetForeignKey.SetDependentToPrincipal(sourceForeignKey.DependentToPrincipal.Name) + : targetForeignKey.SetDependentToPrincipal(sourceForeignKey.DependentToPrincipal.GetIdentifyingMemberInfo()); + Copy(sourceForeignKey.DependentToPrincipal, clonedNavigation!); + } + + if (sourceForeignKey.PrincipalToDependent != null) + { + var clonedNavigation = sourceForeignKey.PrincipalToDependent.IsShadowProperty() + ? targetForeignKey.SetPrincipalToDependent(sourceForeignKey.PrincipalToDependent.Name) + : targetForeignKey.SetPrincipalToDependent(sourceForeignKey.PrincipalToDependent.GetIdentifyingMemberInfo()); + Copy(sourceForeignKey.PrincipalToDependent, clonedNavigation!); + } + + targetForeignKey.AddAnnotations(sourceForeignKey.GetAnnotations() + .Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name))); + } + + protected virtual void Copy(IReadOnlyNavigation sourceNavigation, IMutableNavigation targetNavigation) + { + if (sourceNavigation.FieldInfo is FieldInfo fieldInfo) + { + targetNavigation.FieldInfo = fieldInfo; + } + + targetNavigation.SetPropertyAccessMode(sourceNavigation.GetPropertyAccessMode()); + targetNavigation.SetIsEagerLoaded(sourceNavigation.IsEagerLoaded); + targetNavigation.SetLazyLoadingEnabled(sourceNavigation.LazyLoadingEnabled); + targetNavigation.AddAnnotations(sourceNavigation.GetAnnotations() + .Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name))); + } + + protected virtual void Copy(IReadOnlySkipNavigation sourceNavigation, IMutableSkipNavigation targetNavigation) + { + if (sourceNavigation.FieldInfo is FieldInfo fieldInfo) + { + targetNavigation.FieldInfo = fieldInfo; + } + + targetNavigation.SetPropertyAccessMode(sourceNavigation.GetPropertyAccessMode()); + targetNavigation.SetIsEagerLoaded(sourceNavigation.IsEagerLoaded); + targetNavigation.SetLazyLoadingEnabled(sourceNavigation.LazyLoadingEnabled); + targetNavigation.AddAnnotations(sourceNavigation.GetAnnotations().Where(a => !CoreAnnotationNames.AllNames.Contains(a.Name))); + if (sourceNavigation.ForeignKey != null) + { + var targetDependentType = targetNavigation.DeclaringEntityType.Model.FindEntityType( + sourceNavigation.ForeignKey.DeclaringEntityType.Name)!; + var targetPrincipalType = targetNavigation.DeclaringEntityType.Model.FindEntityType( + sourceNavigation.ForeignKey.PrincipalEntityType.Name)!; + var targetKey = targetPrincipalType.FindKey( + sourceNavigation.ForeignKey.PrincipalKey.Properties.Select(p => targetPrincipalType.FindProperty(p.Name)!).ToList())!; + var targetForeignKey = targetDependentType.FindForeignKey( + sourceNavigation.ForeignKey.Properties.Select(p => targetDependentType.FindProperty(p.Name)!).ToList(), + targetKey, + targetPrincipalType)!; + targetNavigation.SetForeignKey(targetForeignKey); + } + + if (sourceNavigation.Inverse != null) + { + var targetEntityType = targetNavigation.DeclaringEntityType.Model.FindEntityType( + sourceNavigation.Inverse.DeclaringEntityType.Name)!; + targetNavigation.SetInverse( + targetEntityType.FindSkipNavigation(sourceNavigation.Inverse.Name)); + } + } +} diff --git a/test/EFCore.Specification.Tests/TestUtilities/TestHelpers.cs b/test/EFCore.Specification.Tests/TestUtilities/TestHelpers.cs index fed9a169753..c03471bfb52 100644 --- a/test/EFCore.Specification.Tests/TestUtilities/TestHelpers.cs +++ b/test/EFCore.Specification.Tests/TestUtilities/TestHelpers.cs @@ -189,9 +189,11 @@ public TestModelBuilder CreateConventionBuilder( IDiagnosticsLogger validationLogger = null, Action configureConventions = null, Func configureContext = null, - IServiceCollection customServices = null) + Func addServices = null) { - customServices ??= new ServiceCollection(); + var customServices = new ServiceCollection(); + addServices?.Invoke(customServices); + if (modelLogger != null) { customServices.AddScoped(_ => modelLogger); @@ -202,11 +204,10 @@ public TestModelBuilder CreateConventionBuilder( customServices.AddScoped(_ => validationLogger); } + var optionsBuilder = UseProviderOptions(new DbContextOptionsBuilder()); var services = configureContext == null - ? CreateContextServices(customServices) - : CreateContextServices( - customServices, - configureContext(UseProviderOptions(new DbContextOptionsBuilder())).Options); + ? CreateContextServices(customServices, optionsBuilder.Options) + : CreateContextServices(customServices, configureContext(optionsBuilder).Options); return CreateConventionBuilder(services, configureConventions, validationLogger); } @@ -247,6 +248,8 @@ public InternalEntityEntry CreateInternalEntry( return entry; } + public virtual ModelAsserter ModelAsserter => ModelAsserter.Instance; + private static int AssertResults(IList expected, IList actual) { Assert.Equal(expected.Count, actual.Count); diff --git a/test/EFCore.Specification.Tests/TestUtilities/TestValueConverterComparer.cs b/test/EFCore.Specification.Tests/TestUtilities/TestValueConverterComparer.cs new file mode 100644 index 00000000000..634570a7711 --- /dev/null +++ b/test/EFCore.Specification.Tests/TestUtilities/TestValueConverterComparer.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// ReSharper disable PossibleNullReferenceException +namespace Microsoft.EntityFrameworkCore.TestUtilities; + +public class TestValueConverterComparer : IEqualityComparer +{ + public static readonly TestValueConverterComparer Instance = new(); + + private TestValueConverterComparer() + { + } + + public bool Equals(ValueConverter x, ValueConverter y) + => x == null + ? y == null + : y == null + ? false + : ExpressionEqualityComparer.Instance.Equals(x.ConvertFromProviderExpression, y.ConvertFromProviderExpression) + && ExpressionEqualityComparer.Instance.Equals(x.ConvertToProviderExpression, y.ConvertToProviderExpression); + + public int GetHashCode(ValueConverter obj) + => ExpressionEqualityComparer.Instance.GetHashCode(obj.ConvertFromProviderExpression) + ^ ExpressionEqualityComparer.Instance.GetHashCode(obj.ConvertToProviderExpression); +} diff --git a/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderGenericTest.cs b/test/EFCore.SqlServer.FunctionalTests/ModelBuilding/SqlServerModelBuilderGenericTest.cs similarity index 51% rename from test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderGenericTest.cs rename to test/EFCore.SqlServer.FunctionalTests/ModelBuilding/SqlServerModelBuilderGenericTest.cs index f5017e99315..fdf1fa1ce67 100644 --- a/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderGenericTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/ModelBuilding/SqlServerModelBuilderGenericTest.cs @@ -8,107 +8,99 @@ namespace Microsoft.EntityFrameworkCore.ModelBuilding; public class SqlServerModelBuilderGenericTest : SqlServerModelBuilderTestBase { - public class SqlServerGenericNonRelationship : SqlServerNonRelationship, IClassFixture + public class SqlServerGenericNonRelationship : SqlServerNonRelationship { public SqlServerGenericNonRelationship(SqlServerModelBuilderFixture fixture) : base(fixture) { } - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, + protected override TestModelBuilder CreateModelBuilder( Action? configure) - => new ModelBuilderGenericTest.GenericTestModelBuilder(testHelpers, configure); + => new GenericTestModelBuilder(Fixture, configure); } - public class SqlServerGenericComplexType : SqlServerComplexType, IClassFixture + public class SqlServerGenericComplexType : SqlServerComplexType { public SqlServerGenericComplexType(SqlServerModelBuilderFixture fixture) : base(fixture) { } - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, + protected override TestModelBuilder CreateModelBuilder( Action? configure) - => new ModelBuilderGenericTest.GenericTestModelBuilder(testHelpers, configure); + => new GenericTestModelBuilder(Fixture, configure); } - public class SqlServerGenericInheritance : SqlServerInheritance, IClassFixture + public class SqlServerGenericInheritance : SqlServerInheritance { public SqlServerGenericInheritance(SqlServerModelBuilderFixture fixture) : base(fixture) { } - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, + protected override TestModelBuilder CreateModelBuilder( Action? configure) - => new ModelBuilderGenericTest.GenericTestModelBuilder(testHelpers, configure); + => new GenericTestModelBuilder(Fixture, configure); } - public class SqlServerGenericOneToMany : SqlServerOneToMany, IClassFixture + public class SqlServerGenericOneToMany : SqlServerOneToMany { public SqlServerGenericOneToMany(SqlServerModelBuilderFixture fixture) : base(fixture) { } - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, + protected override TestModelBuilder CreateModelBuilder( Action? configure) - => new ModelBuilderGenericTest.GenericTestModelBuilder(testHelpers, configure); + => new GenericTestModelBuilder(Fixture, configure); } - public class SqlServerGenericManyToOne : SqlServerManyToOne, IClassFixture + public class SqlServerGenericManyToOne : SqlServerManyToOne { public SqlServerGenericManyToOne(SqlServerModelBuilderFixture fixture) : base(fixture) { } - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, + protected override TestModelBuilder CreateModelBuilder( Action? configure) - => new ModelBuilderGenericTest.GenericTestModelBuilder(testHelpers, configure); + => new GenericTestModelBuilder(Fixture, configure); } - public class SqlServerGenericOneToOne : SqlServerOneToOne, IClassFixture + public class SqlServerGenericOneToOne : SqlServerOneToOne { public SqlServerGenericOneToOne(SqlServerModelBuilderFixture fixture) : base(fixture) { } - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, + protected override TestModelBuilder CreateModelBuilder( Action? configure) - => new ModelBuilderGenericTest.GenericTestModelBuilder(testHelpers, configure); + => new GenericTestModelBuilder(Fixture, configure); } - public class SqlServerGenericManyToMany : SqlServerManyToMany, IClassFixture + public class SqlServerGenericManyToMany : SqlServerManyToMany { public SqlServerGenericManyToMany(SqlServerModelBuilderFixture fixture) : base(fixture) { } - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, + protected override TestModelBuilder CreateModelBuilder( Action? configure) - => new ModelBuilderGenericTest.GenericTestModelBuilder(testHelpers, configure); + => new GenericTestModelBuilder(Fixture, configure); } - public class SqlServerGenericOwnedTypes : SqlServerOwnedTypes, IClassFixture + public class SqlServerGenericOwnedTypes : SqlServerOwnedTypes { public SqlServerGenericOwnedTypes(SqlServerModelBuilderFixture fixture) : base(fixture) { } - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, + protected override TestModelBuilder CreateModelBuilder( Action? configure) - => new ModelBuilderGenericTest.GenericTestModelBuilder(testHelpers, configure); + => new GenericTestModelBuilder(Fixture, configure); } } diff --git a/test/EFCore.SqlServer.FunctionalTests/ModelBuilding/SqlServerModelBuilderNonGenericTest.cs b/test/EFCore.SqlServer.FunctionalTests/ModelBuilding/SqlServerModelBuilderNonGenericTest.cs new file mode 100644 index 00000000000..19c64c46f7a --- /dev/null +++ b/test/EFCore.SqlServer.FunctionalTests/ModelBuilding/SqlServerModelBuilderNonGenericTest.cs @@ -0,0 +1,98 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#nullable enable + +// ReSharper disable InconsistentNaming +namespace Microsoft.EntityFrameworkCore.ModelBuilding; + +public class SqlServerModelBuilderNonGenericTest : SqlServerModelBuilderTestBase +{ + public class SqlServerNonGenericNonRelationship : SqlServerNonRelationship + { + public SqlServerNonGenericNonRelationship(SqlServerModelBuilderFixture fixture) + : base(fixture) + { + } + + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new NonGenericTestModelBuilder(Fixture, configure); + } + + public class SqlServerNonGenericComplexType : SqlServerComplexType + { + public SqlServerNonGenericComplexType(SqlServerModelBuilderFixture fixture) + : base(fixture) + { + } + + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new NonGenericTestModelBuilder(Fixture, configure); + } + + public class SqlServerNonGenericInheritance : SqlServerInheritance + { + public SqlServerNonGenericInheritance(SqlServerModelBuilderFixture fixture) + : base(fixture) + { + } + + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new NonGenericTestModelBuilder(Fixture, configure); + } + + public class SqlServerNonGenericOneToMany : SqlServerOneToMany + { + public SqlServerNonGenericOneToMany(SqlServerModelBuilderFixture fixture) + : base(fixture) + { + } + + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new NonGenericTestModelBuilder(Fixture, configure); + } + + public class SqlServerNonGenericManyToOne : SqlServerManyToOne + { + public SqlServerNonGenericManyToOne(SqlServerModelBuilderFixture fixture) + : base(fixture) + { + } + + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new NonGenericTestModelBuilder(Fixture, configure); + } + + public class SqlServerNonGenericOneToOne : SqlServerOneToOne + { + public SqlServerNonGenericOneToOne(SqlServerModelBuilderFixture fixture) + : base(fixture) + { + } + + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new NonGenericTestModelBuilder(Fixture, configure); + } + + public class SqlServerNonGenericManyToMany : SqlServerManyToMany + { + public SqlServerNonGenericManyToMany(SqlServerModelBuilderFixture fixture) + : base(fixture) + { + } + + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new NonGenericTestModelBuilder(Fixture, configure); + } + + public class SqlServerNonGenericOwnedTypes : SqlServerOwnedTypes + { + public SqlServerNonGenericOwnedTypes(SqlServerModelBuilderFixture fixture) + : base(fixture) + { + } + + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) + => new NonGenericTestModelBuilder(Fixture, configure); + } +} diff --git a/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderTestBase.cs b/test/EFCore.SqlServer.FunctionalTests/ModelBuilding/SqlServerModelBuilderTestBase.cs similarity index 94% rename from test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderTestBase.cs rename to test/EFCore.SqlServer.FunctionalTests/ModelBuilding/SqlServerModelBuilderTestBase.cs index 33a81dcc794..f1a9c8a171c 100644 --- a/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderTestBase.cs +++ b/test/EFCore.SqlServer.FunctionalTests/ModelBuilding/SqlServerModelBuilderTestBase.cs @@ -302,9 +302,6 @@ protected class SqlVariantEntity [Column(TypeName = "sql_variant")] public object? Value { get; set; } } - - protected override TestModelBuilder CreateModelBuilder(Action? configure = null) - => CreateTestModelBuilder(SqlServerTestHelpers.Instance, configure); } public abstract class SqlServerComplexType : RelationalComplexTypeTestBase, IClassFixture @@ -313,9 +310,6 @@ public SqlServerComplexType(SqlServerModelBuilderFixture fixture) : base(fixture) { } - - protected override TestModelBuilder CreateModelBuilder(Action? configure = null) - => CreateTestModelBuilder(SqlServerTestHelpers.Instance, configure); } public abstract class SqlServerInheritance : RelationalInheritanceTestBase, IClassFixture @@ -644,9 +638,6 @@ public void Adding_conflicting_check_constraint_to_derived_type_before_base_thro () => modelBuilder.Entity().HasBaseType()).Message); } - protected override TestModelBuilder CreateModelBuilder(Action? configure = null) - => CreateTestModelBuilder(SqlServerTestHelpers.Instance, configure); - protected class Parent { public int Id { get; set; } @@ -735,9 +726,6 @@ protected class Company protected class User { } - - protected override TestModelBuilder CreateModelBuilder(Action? configure = null) - => CreateTestModelBuilder(SqlServerTestHelpers.Instance, configure); } public abstract class SqlServerManyToOne : RelationalManyToOneTestBase, IClassFixture @@ -746,9 +734,6 @@ public SqlServerManyToOne(SqlServerModelBuilderFixture fixture) : base(fixture) { } - - protected override TestModelBuilder CreateModelBuilder(Action? configure = null) - => CreateTestModelBuilder(SqlServerTestHelpers.Instance, configure); } public abstract class SqlServerOneToOne : RelationalOneToOneTestBase, IClassFixture @@ -757,9 +742,6 @@ public SqlServerOneToOne(SqlServerModelBuilderFixture fixture) : base(fixture) { } - - protected override TestModelBuilder CreateModelBuilder(Action? configure = null) - => CreateTestModelBuilder(SqlServerTestHelpers.Instance, configure); } public abstract class SqlServerManyToMany : RelationalManyToManyTestBase, IClassFixture @@ -824,9 +806,6 @@ public virtual void Join_entity_type_uses_default_schema_if_related_are_differen Assert.Same(productsFk, productCategoryType.GetForeignKeys().First()); Assert.Equal(2, productCategoryType.GetForeignKeys().Count()); } - - protected override TestModelBuilder CreateModelBuilder(Action? configure = null) - => CreateTestModelBuilder(SqlServerTestHelpers.Instance, configure); } public abstract class SqlServerOwnedTypes : RelationalOwnedTypesTestBase, IClassFixture @@ -1264,90 +1243,6 @@ public virtual void Owner_can_be_mapped_to_a_view() Assert.Null(owned.GetSchema()); } - public override void Can_configure_owned_type() - { - var modelBuilder = CreateModelBuilder(); - - modelBuilder.Ignore(); - modelBuilder.Ignore(); - - var ownedBuilder = modelBuilder.Entity().OwnsOne(c => c.Details) - .ToTable( - "OtherCustomerDetails", tb => - tb.HasCheckConstraint("CK_CustomerDetails_T", "AlternateKey <> 0").HasName("CK_Guid")); - ownedBuilder.Property(d => d.CustomerId); - ownedBuilder.HasIndex(d => d.CustomerId); - ownedBuilder.WithOwner(d => (OtherCustomer?)d.Customer) - .HasPrincipalKey(c => c.AlternateKey); - - modelBuilder.Entity().OwnsOne( - c => c.Details, b => - { - b.ToTable( - "SpecialCustomerDetails", tb => - tb.HasCheckConstraint("CK_CustomerDetails_T", "AlternateKey <> 0").HasName("CK_Guid")); - b.Property(d => d.CustomerId); - b.HasIndex(d => d.CustomerId); - b.WithOwner(d => (SpecialCustomer?)d.Customer) - .HasPrincipalKey(c => c.AlternateKey); - }); - - var model = modelBuilder.FinalizeModel(); - - var owner1 = model.FindEntityType(typeof(OtherCustomer))!; - Assert.Equal(typeof(OtherCustomer).FullName, owner1.Name); - AssertOwnership(owner1); - - var owner2 = model.FindEntityType(typeof(SpecialCustomer))!; - Assert.Equal(typeof(SpecialCustomer).FullName, owner2.Name); - AssertOwnership(owner2); - - Assert.Null(model.FindEntityType(typeof(CustomerDetails))); - Assert.Equal(2, model.GetEntityTypes().Count(e => e.ClrType == typeof(CustomerDetails))); - - static void AssertOwnership(IEntityType owner) - { - var ownership1 = owner.FindNavigation(nameof(Customer.Details))!.ForeignKey; - Assert.True(ownership1.IsOwnership); - Assert.Equal(nameof(Customer.Details), ownership1.PrincipalToDependent?.Name); - Assert.Equal("CustomerAlternateKey", ownership1.Properties.Single().Name); - Assert.Equal(nameof(Customer.AlternateKey), ownership1.PrincipalKey.Properties.Single().Name); - var owned = ownership1.DeclaringEntityType; - Assert.Equal(owner.ShortName() + "Details", owned.GetTableName()); - var checkConstraint = owned.GetCheckConstraints().Single(); - Assert.Same(owned, checkConstraint.EntityType); - Assert.Equal("CK_CustomerDetails_T", checkConstraint.ModelName); - Assert.Equal("AlternateKey <> 0", checkConstraint.Sql); - Assert.Equal("CK_Guid", checkConstraint.Name); - Assert.Single(owned.GetForeignKeys()); - var index = owned.GetIndexes().Single(); - Assert.Same(owned, index.DeclaringEntityType); - Assert.Equal(nameof(CustomerDetails.CustomerId), index.Properties.Single().Name); - Assert.Equal( - new[] { "CustomerAlternateKey", nameof(CustomerDetails.CustomerId), nameof(CustomerDetails.Id) }, - owned.GetProperties().Select(p => p.Name)); - } - } - - public override void Can_configure_owned_type_key() - { - var modelBuilder = CreateModelBuilder(); - var model = modelBuilder.Model; - - modelBuilder.Entity().OwnsOne(c => c.Details) - .ToTable("Details") - .HasKey(c => c.Id); - - modelBuilder.FinalizeModel(); - - var owner = model.FindEntityType(typeof(Customer))!; - var owned = owner.FindNavigation(nameof(Customer.Details))!.ForeignKey.DeclaringEntityType; - Assert.Equal( - new[] { nameof(CustomerDetails.Id), nameof(CustomerDetails.CustomerId) }, - owned.GetProperties().Select(p => p.Name).ToArray()); - Assert.Equal(nameof(CustomerDetails.Id), owned.FindPrimaryKey()!.Properties.Single().Name); - } - [ConditionalFact] public virtual void Temporal_table_default_settings() { @@ -2225,13 +2120,11 @@ public virtual void Json_entity_with_nested_structure_same_property_names_() var ownedEntities = model.FindEntityTypes(typeof(OwnedEntity)); Assert.Equal(16, ownedEntities.Count()); } - - protected override TestModelBuilder CreateModelBuilder(Action? configure = null) - => CreateTestModelBuilder(SqlServerTestHelpers.Instance, configure); } public class SqlServerModelBuilderFixture : RelationalModelBuilderFixture { + public override TestHelpers TestHelpers => SqlServerTestHelpers.Instance; } public abstract class TestTemporalTableBuilder diff --git a/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerTestModelBuilderExtensions.cs b/test/EFCore.SqlServer.FunctionalTests/ModelBuilding/SqlServerTestModelBuilderExtensions.cs similarity index 100% rename from test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerTestModelBuilderExtensions.cs rename to test/EFCore.SqlServer.FunctionalTests/ModelBuilding/SqlServerTestModelBuilderExtensions.cs diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs index e736152d913..9bfee23c2f7 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs @@ -9278,10 +9278,14 @@ public virtual async Task Method_call_translators_are_invoked_for_indexer_if_not { var contextFactory = await InitializeAsync( seed: c => c.Seed(), - addServices: c => c.TryAddEnumerable( - new ServiceDescriptor( - typeof(IMethodCallTranslatorPlugin), typeof(MyContext23410.JsonMethodCallTranslatorPlugin), - ServiceLifetime.Scoped))); + addServices: c => + { + c.TryAddEnumerable( + new ServiceDescriptor( + typeof(IMethodCallTranslatorPlugin), typeof(MyContext23410.JsonMethodCallTranslatorPlugin), + ServiceLifetime.Scoped)); + return c; + }); using (var context = contextFactory.CreateContext()) { diff --git a/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/BigModel/DbContextModelBuilder.cs b/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/BigModel/DbContextModelBuilder.cs index c5d2ce84cdf..a8c39f1c273 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/BigModel/DbContextModelBuilder.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/BigModel/DbContextModelBuilder.cs @@ -2241,9 +2241,6 @@ private IRelationalModel CreateRelationalModel() RelationalModel.CreateColumnMapping((ColumnBase)valueTypeEnumerableColumnBase, principalDerived.FindProperty("ValueTypeEnumerable")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); RelationalModel.CreateColumnMapping((ColumnBase)valueTypeIListColumnBase, principalDerived.FindProperty("ValueTypeIList")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); RelationalModel.CreateColumnMapping((ColumnBase)valueTypeListColumnBase, principalDerived.FindProperty("ValueTypeList")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); - - var defaultTableMappings5 = new List>(); - principalDerived.SetRuntimeAnnotation("Relational:DefaultMappings", defaultTableMappings5); var microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteTableBase = new TableBase("Microsoft.EntityFrameworkCore.Scaffolding.CompiledModelTestBase+PrincipalDerived>", null, relationalModel); var alternateIdColumnBase0 = new ColumnBase("AlternateId", "uniqueidentifier", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteTableBase); microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteTableBase.Columns.Add("AlternateId", alternateIdColumnBase0); @@ -2252,7 +2249,7 @@ private IRelationalModel CreateRelationalModel() relationalModel.DefaultTables.Add("Microsoft.EntityFrameworkCore.Scaffolding.CompiledModelTestBase+PrincipalDerived>", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteTableBase); var microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteMappingBase = new TableMappingBase(principalDerived, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteTableBase, true); microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteTableBase.AddTypeMapping(microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteMappingBase, false); - defaultTableMappings5.Add(microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteMappingBase); + defaultTableMappings4.Add(microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteMappingBase); RelationalModel.CreateColumnMapping((ColumnBase)alternateIdColumnBase0, principalDerived.FindProperty("AlternateId")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteMappingBase); RelationalModel.CreateColumnMapping((ColumnBase)idColumnBase2, principalDerived.FindProperty("Id")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteMappingBase); @@ -2315,8 +2312,8 @@ private IRelationalModel CreateRelationalModel() var ownedType0 = FindEntityType("Microsoft.EntityFrameworkCore.Scaffolding.CompiledModelTestBase+PrincipalDerived>.ManyOwned#OwnedType")!; - var defaultTableMappings6 = new List>(); - ownedType0.SetRuntimeAnnotation("Relational:DefaultMappings", defaultTableMappings6); + var defaultTableMappings5 = new List>(); + ownedType0.SetRuntimeAnnotation("Relational:DefaultMappings", defaultTableMappings5); var microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteManyOwnedOwnedTypeTableBase = new TableBase("Microsoft.EntityFrameworkCore.Scaffolding.CompiledModelTestBase+PrincipalDerived>.ManyOwned#OwnedType", null, relationalModel); var detailsColumnBase0 = new ColumnBase("Details", "nvarchar(max)", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteManyOwnedOwnedTypeTableBase) { @@ -2374,7 +2371,7 @@ private IRelationalModel CreateRelationalModel() relationalModel.DefaultTables.Add("Microsoft.EntityFrameworkCore.Scaffolding.CompiledModelTestBase+PrincipalDerived>.ManyOwned#OwnedType", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteManyOwnedOwnedTypeTableBase); var microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteManyOwnedOwnedTypeMappingBase = new TableMappingBase(ownedType0, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteManyOwnedOwnedTypeTableBase, true); microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteManyOwnedOwnedTypeTableBase.AddTypeMapping(microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteManyOwnedOwnedTypeMappingBase, false); - defaultTableMappings6.Add(microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteManyOwnedOwnedTypeMappingBase); + defaultTableMappings5.Add(microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteManyOwnedOwnedTypeMappingBase); RelationalModel.CreateColumnMapping((ColumnBase)idColumnBase3, ownedType0.FindProperty("Id")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteManyOwnedOwnedTypeMappingBase); RelationalModel.CreateColumnMapping((ColumnBase)principalDerivedDependentBasebyteAlternateIdColumnBase, ownedType0.FindProperty("PrincipalDerivedAlternateId")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteManyOwnedOwnedTypeMappingBase); RelationalModel.CreateColumnMapping((ColumnBase)principalDerivedDependentBasebyteIdColumnBase, ownedType0.FindProperty("PrincipalDerivedId")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteManyOwnedOwnedTypeMappingBase); @@ -2473,8 +2470,8 @@ private IRelationalModel CreateRelationalModel() var principalBasePrincipalDerivedDependentBasebyte = FindEntityType("PrincipalBasePrincipalDerived>")!; - var defaultTableMappings7 = new List>(); - principalBasePrincipalDerivedDependentBasebyte.SetRuntimeAnnotation("Relational:DefaultMappings", defaultTableMappings7); + var defaultTableMappings6 = new List>(); + principalBasePrincipalDerivedDependentBasebyte.SetRuntimeAnnotation("Relational:DefaultMappings", defaultTableMappings6); var principalBasePrincipalDerivedDependentBasebyteTableBase = new TableBase("PrincipalBasePrincipalDerived>", null, relationalModel); var derivedsAlternateIdColumnBase = new ColumnBase("DerivedsAlternateId", "uniqueidentifier", principalBasePrincipalDerivedDependentBasebyteTableBase); principalBasePrincipalDerivedDependentBasebyteTableBase.Columns.Add("DerivedsAlternateId", derivedsAlternateIdColumnBase); @@ -2492,7 +2489,7 @@ private IRelationalModel CreateRelationalModel() relationalModel.DefaultTables.Add("PrincipalBasePrincipalDerived>", principalBasePrincipalDerivedDependentBasebyteTableBase); var principalBasePrincipalDerivedDependentBasebyteMappingBase = new TableMappingBase(principalBasePrincipalDerivedDependentBasebyte, principalBasePrincipalDerivedDependentBasebyteTableBase, true); principalBasePrincipalDerivedDependentBasebyteTableBase.AddTypeMapping(principalBasePrincipalDerivedDependentBasebyteMappingBase, false); - defaultTableMappings7.Add(principalBasePrincipalDerivedDependentBasebyteMappingBase); + defaultTableMappings6.Add(principalBasePrincipalDerivedDependentBasebyteMappingBase); RelationalModel.CreateColumnMapping((ColumnBase)derivedsAlternateIdColumnBase, principalBasePrincipalDerivedDependentBasebyte.FindProperty("DerivedsAlternateId")!, principalBasePrincipalDerivedDependentBasebyteMappingBase); RelationalModel.CreateColumnMapping((ColumnBase)derivedsIdColumnBase, principalBasePrincipalDerivedDependentBasebyte.FindProperty("DerivedsId")!, principalBasePrincipalDerivedDependentBasebyteMappingBase); RelationalModel.CreateColumnMapping((ColumnBase)principalsAlternateIdColumnBase, principalBasePrincipalDerivedDependentBasebyte.FindProperty("PrincipalsAlternateId")!, principalBasePrincipalDerivedDependentBasebyteMappingBase); diff --git a/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/Tpc/DependentBaseEntityType.cs b/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/Tpc/DependentBaseEntityType.cs index f051e9d4194..a21f4920664 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/Tpc/DependentBaseEntityType.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/Tpc/DependentBaseEntityType.cs @@ -73,6 +73,7 @@ public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType bas var index = runtimeEntityType.AddIndex( new[] { principalId }, unique: true); + index.AddAnnotation("Relational:Filter", "[PrincipalId] IS NOT NULL"); return runtimeEntityType; } diff --git a/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/Tpc/PrincipalBaseEntityType.cs b/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/Tpc/PrincipalBaseEntityType.cs index d8de5489727..dc84aaf60a4 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/Tpc/PrincipalBaseEntityType.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/Tpc/PrincipalBaseEntityType.cs @@ -626,6 +626,7 @@ public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType bas new[] { principalBaseId }, name: "PrincipalIndex", unique: true); + principalIndex.AddAnnotation("Relational:Filter", "AlternateId <> NULL"); principalIndex.AddAnnotation("Relational:Name", "PIX"); return runtimeEntityType; diff --git a/test/EFCore.SqlServer.FunctionalTests/SqlServerValueGenerationScenariosTestBase.cs b/test/EFCore.SqlServer.FunctionalTests/SqlServerValueGenerationScenariosTestBase.cs index 4951b462758..0789376cca0 100644 --- a/test/EFCore.SqlServer.FunctionalTests/SqlServerValueGenerationScenariosTestBase.cs +++ b/test/EFCore.SqlServer.FunctionalTests/SqlServerValueGenerationScenariosTestBase.cs @@ -1148,7 +1148,10 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) [ConditionalFact] public void Insert_and_update_with_computed_column_with_querying_function() { - using var testStore = SqlServerTestStore.CreateInitialized(DatabaseName); + SqlServerTestStore testStore = null; + try + { + testStore = SqlServerTestStore.CreateInitialized(DatabaseName); using (var context = new BlogContextComputedColumnWithTriggerMetadata(testStore.Name, OnModelCreating, IntSentinel, StringSentinel)) { context.GetService().CreateTables(); @@ -1167,8 +1170,6 @@ RETURN @FullName context.Database.ExecuteSqlRaw("ALTER TABLE dbo.FullNameBlogs ADD FullName AS [dbo].[GetFullName]([Id]); "); } - try - { using (var context = new BlogContextComputedColumnWithTriggerMetadata( testStore.Name, OnModelCreating, IntSentinel, StringSentinel)) { @@ -1230,9 +1231,10 @@ RETURN @FullName finally { using var context = new BlogContextComputedColumnWithTriggerMetadata( - testStore.Name, OnModelCreating, IntSentinel, StringSentinel); + DatabaseName, OnModelCreating, IntSentinel, StringSentinel); context.Database.ExecuteSqlRaw("ALTER TABLE dbo.FullNameBlogs DROP COLUMN FullName;"); context.Database.ExecuteSqlRaw("DROP FUNCTION [dbo].[GetFullName];"); + testStore?.Dispose(); } } diff --git a/test/EFCore.SqlServer.HierarchyId.Tests/ModelCodeGeneratorTestBase.cs b/test/EFCore.SqlServer.HierarchyId.Tests/ModelCodeGeneratorTestBase.cs index 06174e68d0f..23ab0f4167c 100644 --- a/test/EFCore.SqlServer.HierarchyId.Tests/ModelCodeGeneratorTestBase.cs +++ b/test/EFCore.SqlServer.HierarchyId.Tests/ModelCodeGeneratorTestBase.cs @@ -17,18 +17,13 @@ protected void Test( ModelCodeGenerationOptions options, Action assertScaffold) { - var designServices = new ServiceCollection(); - AddModelServices(designServices); - - var modelBuilder = SqlServerTestHelpers.Instance.CreateConventionBuilder(customServices: designServices); + var modelBuilder = SqlServerTestHelpers.Instance.CreateConventionBuilder(addServices: AddModelServices); modelBuilder.Model.RemoveAnnotation(CoreAnnotationNames.ProductVersion); buildModel(modelBuilder); var model = modelBuilder.FinalizeModel(designTime: true, skipValidation: true); - var services = CreateServices(); - AddScaffoldingServices(services); - + var services = AddScaffoldingServices(CreateServices()); var generator = services.BuildServiceProvider(validateScopes: true) .GetRequiredService(); @@ -51,13 +46,11 @@ private static IServiceCollection CreateServices() return services; } - protected virtual void AddModelServices(IServiceCollection services) - { - } + protected virtual IServiceCollection AddModelServices(IServiceCollection services) + => services; - protected virtual void AddScaffoldingServices(IServiceCollection services) - { - } + protected virtual IServiceCollection AddScaffoldingServices(IServiceCollection services) + => services; protected static void AssertFileContents( string expectedCode, diff --git a/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderNonGenericTest.cs b/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderNonGenericTest.cs deleted file mode 100644 index 8597c0d254d..00000000000 --- a/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderNonGenericTest.cs +++ /dev/null @@ -1,114 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#nullable enable - -// ReSharper disable InconsistentNaming -namespace Microsoft.EntityFrameworkCore.ModelBuilding; - -public class SqlServerModelBuilderNonGenericTest : SqlServerModelBuilderTestBase -{ - public class SqlServerNonGenericNonRelationship : SqlServerNonRelationship, IClassFixture - { - public SqlServerNonGenericNonRelationship(SqlServerModelBuilderFixture fixture) - : base(fixture) - { - } - - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new ModelBuilderNonGenericTest.NonGenericTestModelBuilder(testHelpers, configure); - } - - public class SqlServerNonGenericComplexType : SqlServerComplexType, IClassFixture - { - public SqlServerNonGenericComplexType(SqlServerModelBuilderFixture fixture) - : base(fixture) - { - } - - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new ModelBuilderNonGenericTest.NonGenericTestModelBuilder(testHelpers, configure); - } - - public class SqlServerNonGenericInheritance : SqlServerInheritance, IClassFixture - { - public SqlServerNonGenericInheritance(SqlServerModelBuilderFixture fixture) - : base(fixture) - { - } - - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new ModelBuilderNonGenericTest.NonGenericTestModelBuilder(testHelpers, configure); - } - - public class SqlServerNonGenericOneToMany : SqlServerOneToMany, IClassFixture - { - public SqlServerNonGenericOneToMany(SqlServerModelBuilderFixture fixture) - : base(fixture) - { - } - - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new ModelBuilderNonGenericTest.NonGenericTestModelBuilder(testHelpers, configure); - } - - public class SqlServerNonGenericManyToOne : SqlServerManyToOne, IClassFixture - { - public SqlServerNonGenericManyToOne(SqlServerModelBuilderFixture fixture) - : base(fixture) - { - } - - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new ModelBuilderNonGenericTest.NonGenericTestModelBuilder(testHelpers, configure); - } - - public class SqlServerNonGenericOneToOne : SqlServerOneToOne, IClassFixture - { - public SqlServerNonGenericOneToOne(SqlServerModelBuilderFixture fixture) - : base(fixture) - { - } - - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new ModelBuilderNonGenericTest.NonGenericTestModelBuilder(testHelpers, configure); - } - - public class SqlServerNonGenericManyToMany : SqlServerManyToMany, IClassFixture - { - public SqlServerNonGenericManyToMany(SqlServerModelBuilderFixture fixture) - : base(fixture) - { - } - - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new ModelBuilderNonGenericTest.NonGenericTestModelBuilder(testHelpers, configure); - } - - public class SqlServerNonGenericOwnedTypes : SqlServerOwnedTypes, IClassFixture - { - public SqlServerNonGenericOwnedTypes(SqlServerModelBuilderFixture fixture) - : base(fixture) - { - } - - protected override TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure) - => new ModelBuilderNonGenericTest.NonGenericTestModelBuilder(testHelpers, configure); - } -} diff --git a/test/EFCore.Sqlite.FunctionalTests/ModelBuilding/SqliteModelBuilderGenericTest.cs b/test/EFCore.Sqlite.FunctionalTests/ModelBuilding/SqliteModelBuilderGenericTest.cs new file mode 100644 index 00000000000..cb91bb9a859 --- /dev/null +++ b/test/EFCore.Sqlite.FunctionalTests/ModelBuilding/SqliteModelBuilderGenericTest.cs @@ -0,0 +1,106 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#nullable enable + +// ReSharper disable InconsistentNaming +namespace Microsoft.EntityFrameworkCore.ModelBuilding; + +public class SqliteModelBuilderGenericTest : SqliteModelBuilderTestBase +{ + public class SqlServerGenericNonRelationship : SqliteNonRelationship + { + public SqlServerGenericNonRelationship(SqliteModelBuilderFixture fixture) + : base(fixture) + { + } + + protected override TestModelBuilder CreateModelBuilder( + Action? configure) + => new GenericTestModelBuilder(Fixture, configure); + } + + public class SqlServerGenericComplexType : SqliteComplexType + { + public SqlServerGenericComplexType(SqliteModelBuilderFixture fixture) + : base(fixture) + { + } + + protected override TestModelBuilder CreateModelBuilder( + Action? configure) + => new GenericTestModelBuilder(Fixture, configure); + } + + public class SqlServerGenericInheritance : SqliteInheritance + { + public SqlServerGenericInheritance(SqliteModelBuilderFixture fixture) + : base(fixture) + { + } + + protected override TestModelBuilder CreateModelBuilder( + Action? configure) + => new GenericTestModelBuilder(Fixture, configure); + } + + public class SqlServerGenericOneToMany : SqliteOneToMany + { + public SqlServerGenericOneToMany(SqliteModelBuilderFixture fixture) + : base(fixture) + { + } + + protected override TestModelBuilder CreateModelBuilder( + Action? configure) + => new GenericTestModelBuilder(Fixture, configure); + } + + public class SqlServerGenericManyToOne : SqliteManyToOne + { + public SqlServerGenericManyToOne(SqliteModelBuilderFixture fixture) + : base(fixture) + { + } + + protected override TestModelBuilder CreateModelBuilder( + Action? configure) + => new GenericTestModelBuilder(Fixture, configure); + } + + public class SqlServerGenericOneToOne : SqliteOneToOne + { + public SqlServerGenericOneToOne(SqliteModelBuilderFixture fixture) + : base(fixture) + { + } + + protected override TestModelBuilder CreateModelBuilder( + Action? configure) + => new GenericTestModelBuilder(Fixture, configure); + } + + public class SqlServerGenericManyToMany : SqliteManyToMany + { + public SqlServerGenericManyToMany(SqliteModelBuilderFixture fixture) + : base(fixture) + { + } + + protected override TestModelBuilder CreateModelBuilder( + Action? configure) + => new GenericTestModelBuilder(Fixture, configure); + } + + public class SqlServerGenericOwnedTypes : SqliteOwnedTypes + { + public SqlServerGenericOwnedTypes(SqliteModelBuilderFixture fixture) + : base(fixture) + { + } + + protected override TestModelBuilder CreateModelBuilder( + Action? configure) + => new GenericTestModelBuilder(Fixture, configure); + } +} diff --git a/test/EFCore.Sqlite.FunctionalTests/ModelBuilding/SqliteModelBuilderTestBase.cs b/test/EFCore.Sqlite.FunctionalTests/ModelBuilding/SqliteModelBuilderTestBase.cs new file mode 100644 index 00000000000..aeb7fc5c455 --- /dev/null +++ b/test/EFCore.Sqlite.FunctionalTests/ModelBuilding/SqliteModelBuilderTestBase.cs @@ -0,0 +1,85 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#nullable enable + +using Microsoft.EntityFrameworkCore.Metadata.Internal; +using Microsoft.EntityFrameworkCore.Sqlite.Internal; + +namespace Microsoft.EntityFrameworkCore.ModelBuilding; + +public class SqliteModelBuilderTestBase : RelationalModelBuilderTest +{ + public abstract class SqliteNonRelationship : RelationalNonRelationshipTestBase, IClassFixture + { + public SqliteNonRelationship(SqliteModelBuilderFixture fixture) + : base(fixture) + { + } + } + + public abstract class SqliteComplexType : RelationalComplexTypeTestBase, IClassFixture + { + public SqliteComplexType(SqliteModelBuilderFixture fixture) + : base(fixture) + { + } + } + + public abstract class SqliteInheritance : RelationalInheritanceTestBase, IClassFixture + { + public SqliteInheritance(SqliteModelBuilderFixture fixture) + : base(fixture) + { + } + } + + public abstract class SqliteOneToMany : RelationalOneToManyTestBase, IClassFixture + { + public SqliteOneToMany(SqliteModelBuilderFixture fixture) + : base(fixture) + { + } + } + + public abstract class SqliteManyToOne : RelationalManyToOneTestBase, IClassFixture + { + public SqliteManyToOne(SqliteModelBuilderFixture fixture) + : base(fixture) + { + } + } + + public abstract class SqliteOneToOne : RelationalOneToOneTestBase, IClassFixture + { + public SqliteOneToOne(SqliteModelBuilderFixture fixture) + : base(fixture) + { + } + } + + public abstract class SqliteManyToMany : RelationalManyToManyTestBase, IClassFixture + { + public SqliteManyToMany(SqliteModelBuilderFixture fixture) + : base(fixture) + { + } + } + + public abstract class SqliteOwnedTypes : RelationalOwnedTypesTestBase, IClassFixture + { + public override void Can_use_sproc_mapping_with_owned_reference() + => Assert.Equal(SqliteStrings.StoredProceduresNotSupported("Book.Label#BookLabel"), + Assert.Throws(base.Can_use_sproc_mapping_with_owned_reference).Message); + + public SqliteOwnedTypes(SqliteModelBuilderFixture fixture) + : base(fixture) + { + } + } + + public class SqliteModelBuilderFixture : RelationalModelBuilderFixture + { + public override TestHelpers TestHelpers => SqliteTestHelpers.Instance; + } +} diff --git a/test/EFCore.Sqlite.FunctionalTests/Scaffolding/Baselines/BigModel/DbContextModelBuilder.cs b/test/EFCore.Sqlite.FunctionalTests/Scaffolding/Baselines/BigModel/DbContextModelBuilder.cs index 287c8b24986..45e85876b76 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Scaffolding/Baselines/BigModel/DbContextModelBuilder.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Scaffolding/Baselines/BigModel/DbContextModelBuilder.cs @@ -2310,9 +2310,6 @@ private IRelationalModel CreateRelationalModel() RelationalModel.CreateColumnMapping((ColumnBase)valueTypeEnumerableColumnBase, principalDerived.FindProperty("ValueTypeEnumerable")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); RelationalModel.CreateColumnMapping((ColumnBase)valueTypeIListColumnBase, principalDerived.FindProperty("ValueTypeIList")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); RelationalModel.CreateColumnMapping((ColumnBase)valueTypeListColumnBase, principalDerived.FindProperty("ValueTypeList")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); - - var defaultTableMappings6 = new List>(); - principalDerived.SetRuntimeAnnotation("Relational:DefaultMappings", defaultTableMappings6); var microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteTableBase = new TableBase("Microsoft.EntityFrameworkCore.Scaffolding.CompiledModelTestBase+PrincipalDerived>", null, relationalModel); var alternateIdColumnBase0 = new ColumnBase("AlternateId", "TEXT", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteTableBase); microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteTableBase.Columns.Add("AlternateId", alternateIdColumnBase0); @@ -2321,7 +2318,7 @@ private IRelationalModel CreateRelationalModel() relationalModel.DefaultTables.Add("Microsoft.EntityFrameworkCore.Scaffolding.CompiledModelTestBase+PrincipalDerived>", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteTableBase); var microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteMappingBase = new TableMappingBase(principalDerived, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteTableBase, true); microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteTableBase.AddTypeMapping(microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteMappingBase, false); - defaultTableMappings6.Add(microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteMappingBase); + defaultTableMappings5.Add(microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteMappingBase); RelationalModel.CreateColumnMapping((ColumnBase)alternateIdColumnBase0, principalDerived.FindProperty("AlternateId")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteMappingBase); RelationalModel.CreateColumnMapping((ColumnBase)idColumnBase3, principalDerived.FindProperty("Id")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteMappingBase); @@ -2385,8 +2382,8 @@ private IRelationalModel CreateRelationalModel() var ownedType0 = FindEntityType("Microsoft.EntityFrameworkCore.Scaffolding.CompiledModelTestBase+PrincipalDerived>.ManyOwned#OwnedType")!; - var defaultTableMappings7 = new List>(); - ownedType0.SetRuntimeAnnotation("Relational:DefaultMappings", defaultTableMappings7); + var defaultTableMappings6 = new List>(); + ownedType0.SetRuntimeAnnotation("Relational:DefaultMappings", defaultTableMappings6); var microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteManyOwnedOwnedTypeTableBase = new TableBase("Microsoft.EntityFrameworkCore.Scaffolding.CompiledModelTestBase+PrincipalDerived>.ManyOwned#OwnedType", null, relationalModel); var detailsColumnBase0 = new ColumnBase("Details", "TEXT", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteManyOwnedOwnedTypeTableBase) { @@ -2444,7 +2441,7 @@ private IRelationalModel CreateRelationalModel() relationalModel.DefaultTables.Add("Microsoft.EntityFrameworkCore.Scaffolding.CompiledModelTestBase+PrincipalDerived>.ManyOwned#OwnedType", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteManyOwnedOwnedTypeTableBase); var microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteManyOwnedOwnedTypeMappingBase = new TableMappingBase(ownedType0, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteManyOwnedOwnedTypeTableBase, true); microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteManyOwnedOwnedTypeTableBase.AddTypeMapping(microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteManyOwnedOwnedTypeMappingBase, false); - defaultTableMappings7.Add(microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteManyOwnedOwnedTypeMappingBase); + defaultTableMappings6.Add(microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteManyOwnedOwnedTypeMappingBase); RelationalModel.CreateColumnMapping((ColumnBase)idColumnBase4, ownedType0.FindProperty("Id")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteManyOwnedOwnedTypeMappingBase); RelationalModel.CreateColumnMapping((ColumnBase)principalDerivedDependentBasebyteAlternateIdColumnBase, ownedType0.FindProperty("PrincipalDerivedAlternateId")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteManyOwnedOwnedTypeMappingBase); RelationalModel.CreateColumnMapping((ColumnBase)principalDerivedDependentBasebyteIdColumnBase, ownedType0.FindProperty("PrincipalDerivedId")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalDerivedMicrosoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDependentBasebyteManyOwnedOwnedTypeMappingBase); @@ -2543,8 +2540,8 @@ private IRelationalModel CreateRelationalModel() var principalBasePrincipalDerivedDependentBasebyte = FindEntityType("PrincipalBasePrincipalDerived>")!; - var defaultTableMappings8 = new List>(); - principalBasePrincipalDerivedDependentBasebyte.SetRuntimeAnnotation("Relational:DefaultMappings", defaultTableMappings8); + var defaultTableMappings7 = new List>(); + principalBasePrincipalDerivedDependentBasebyte.SetRuntimeAnnotation("Relational:DefaultMappings", defaultTableMappings7); var principalBasePrincipalDerivedDependentBasebyteTableBase = new TableBase("PrincipalBasePrincipalDerived>", null, relationalModel); var derivedsAlternateIdColumnBase = new ColumnBase("DerivedsAlternateId", "TEXT", principalBasePrincipalDerivedDependentBasebyteTableBase); principalBasePrincipalDerivedDependentBasebyteTableBase.Columns.Add("DerivedsAlternateId", derivedsAlternateIdColumnBase); @@ -2562,7 +2559,7 @@ private IRelationalModel CreateRelationalModel() relationalModel.DefaultTables.Add("PrincipalBasePrincipalDerived>", principalBasePrincipalDerivedDependentBasebyteTableBase); var principalBasePrincipalDerivedDependentBasebyteMappingBase = new TableMappingBase(principalBasePrincipalDerivedDependentBasebyte, principalBasePrincipalDerivedDependentBasebyteTableBase, true); principalBasePrincipalDerivedDependentBasebyteTableBase.AddTypeMapping(principalBasePrincipalDerivedDependentBasebyteMappingBase, false); - defaultTableMappings8.Add(principalBasePrincipalDerivedDependentBasebyteMappingBase); + defaultTableMappings7.Add(principalBasePrincipalDerivedDependentBasebyteMappingBase); RelationalModel.CreateColumnMapping((ColumnBase)derivedsAlternateIdColumnBase, principalBasePrincipalDerivedDependentBasebyte.FindProperty("DerivedsAlternateId")!, principalBasePrincipalDerivedDependentBasebyteMappingBase); RelationalModel.CreateColumnMapping((ColumnBase)derivedsIdColumnBase, principalBasePrincipalDerivedDependentBasebyte.FindProperty("DerivedsId")!, principalBasePrincipalDerivedDependentBasebyteMappingBase); RelationalModel.CreateColumnMapping((ColumnBase)principalsAlternateIdColumnBase, principalBasePrincipalDerivedDependentBasebyte.FindProperty("PrincipalsAlternateId")!, principalBasePrincipalDerivedDependentBasebyteMappingBase); diff --git a/test/EFCore.Tests/EFCore.Tests.csproj b/test/EFCore.Tests/EFCore.Tests.csproj index e8e130056ff..7248ae169d7 100644 --- a/test/EFCore.Tests/EFCore.Tests.csproj +++ b/test/EFCore.Tests/EFCore.Tests.csproj @@ -46,28 +46,4 @@ - - - - - - - TextTemplatingFileGenerator - GiantModel.cs - - - - - - True - True - GiantModel.tt - - - - TextTemplatingFileGenerator - GiantModel.cs - - - diff --git a/test/EFCore.Tests/ModelBuilding/IEntityTypeConfigurationTest.cs b/test/EFCore.Tests/IEntityTypeConfigurationTest.cs similarity index 98% rename from test/EFCore.Tests/ModelBuilding/IEntityTypeConfigurationTest.cs rename to test/EFCore.Tests/IEntityTypeConfigurationTest.cs index 883dcbac682..fc6afdad583 100644 --- a/test/EFCore.Tests/ModelBuilding/IEntityTypeConfigurationTest.cs +++ b/test/EFCore.Tests/IEntityTypeConfigurationTest.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.EntityFrameworkCore.ModelBuilding; +namespace Microsoft.EntityFrameworkCore; public class IEntityTypeConfigurationTest { diff --git a/test/EFCore.Tests/Metadata/Conventions/ConventionSetBuilderTests.cs b/test/EFCore.Tests/Metadata/Conventions/ConventionSetBuilderTests.cs index 089595ca7f6..5eb545a8495 100644 --- a/test/EFCore.Tests/Metadata/Conventions/ConventionSetBuilderTests.cs +++ b/test/EFCore.Tests/Metadata/Conventions/ConventionSetBuilderTests.cs @@ -9,6 +9,31 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Conventions; public class ConventionSetBuilderTests { + [ConditionalFact] + public void Can_create_a_model_builder_with_given_conventions_only() + { + var convention = new TestEntityTypeAddedConvention(); + var conventions = new ConventionSet(); + conventions.EntityTypeAddedConventions.Add(convention); + + var modelBuilder = new ModelBuilder(conventions); + + modelBuilder.Entity(); + + Assert.True(convention.Applied); + Assert.NotNull(modelBuilder.Model.FindEntityType(typeof(Random))); + } + + private class TestEntityTypeAddedConvention : IEntityTypeAddedConvention + { + public bool Applied { get; private set; } + + public void ProcessEntityTypeAdded( + IConventionEntityTypeBuilder entityTypeBuilder, + IConventionContext context) + => Applied = true; + } + [ConditionalFact] public virtual IReadOnlyModel Can_build_a_model_with_default_conventions_without_DI() {