From 7779445e509c13544fbea57b222f5bc5ca6d402b Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Tue, 24 Oct 2023 10:37:27 -0700 Subject: [PATCH] Make ModelBuilderTest asserts more robust and extensible --- eng/Versions.props | 2 + src/EFCore/Metadata/Internal/Model.cs | 6 +- .../CosmosModelBuilderGenericTest.cs | 71 +- .../InMemoryModelBuilderGenericTest.cs | 53 +- .../Metadata/RelationalModelTest.cs | 48 +- .../RelationalModelBuilderTest.cs | 41 + .../EFCore.Specification.Tests.csproj | 1 + .../TestUtilities/ForeignKeyStrictComparer.cs | 40 - .../TestUtilities/MetadataExtensions.cs | 129 -- .../TestUtilities/NavigationComparer.cs | 33 - .../TestUtilities/PropertyComparer.cs | 40 - ...nComparer.cs => TestAnnotationComparer.cs} | 6 +- .../TestUtilities/TestIndexComparer.cs | 36 - .../TestUtilities/TestKeyComparer.cs | 35 - .../SqlServerModelBuilderGenericTest.cs | 56 +- .../SqlServerModelBuilderNonGenericTest.cs | 56 +- .../SqlServerModelBuilderTestBase.cs | 60 +- .../InternalEntryEntrySubscriberTest.cs | 4 +- .../ModelBuilding/ComplexTypeTestBase.cs | 8 + .../ModelBuilding/InheritanceTestBase.cs | 69 +- .../ModelBuilding/ManyToManyTestBase.cs | 11 +- .../ModelBuilding/ManyToOneTestBase.cs | 14 +- ...delBuilderGenericRelationshipStringTest.cs | 22 + ...ModelBuilderGenericRelationshipTypeTest.cs | 10 + .../ModelBuilding/ModelBuilderGenericTest.cs | 42 +- .../ModelBuilderNonGenericStringTest.cs | 22 +- .../ModelBuilderNonGenericTest.cs | 39 + ...lBuilderNonGenericUnqualifiedStringTest.cs | 5 + .../ModelBuilding/ModelBuilderTestBase.cs | 1108 +++++++++++++++-- .../ModelBuilding/NonRelationshipTestBase.cs | 32 +- .../ModelBuilding/OneToManyTestBase.cs | 99 +- .../ModelBuilding/OneToOneTestBase.cs | 10 +- .../ModelBuilding/OwnedTypesTestBase.cs | 9 +- .../ModelBuilding/ShadowEntityTypeTest.cs | 2 +- 34 files changed, 1635 insertions(+), 584 deletions(-) delete mode 100644 test/EFCore.Specification.Tests/TestUtilities/ForeignKeyStrictComparer.cs delete mode 100644 test/EFCore.Specification.Tests/TestUtilities/NavigationComparer.cs delete mode 100644 test/EFCore.Specification.Tests/TestUtilities/PropertyComparer.cs rename test/EFCore.Specification.Tests/TestUtilities/{AnnotationComparer.cs => TestAnnotationComparer.cs} (81%) delete mode 100644 test/EFCore.Specification.Tests/TestUtilities/TestIndexComparer.cs delete mode 100644 test/EFCore.Specification.Tests/TestUtilities/TestKeyComparer.cs diff --git a/eng/Versions.props b/eng/Versions.props index 7753418250d..9f9a830b9eb 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,5 +34,7 @@ 4.5.0 1.1.2-beta1.23371.1 + 2.6.1 + 2.5.3 diff --git a/src/EFCore/Metadata/Internal/Model.cs b/src/EFCore/Metadata/Internal/Model.cs index dfc86b1bad6..646d0f5e3da 100644 --- a/src/EFCore/Metadata/Internal/Model.cs +++ b/src/EFCore/Metadata/Internal/Model.cs @@ -51,9 +51,10 @@ public class Model : ConventionAnnotatable, IMutableModel, IConventionModel, IRu /// 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 Model() + public Model(Guid? modelId = null) : this(new ConventionSet()) { + ModelId = modelId ?? Guid.NewGuid(); } /// @@ -75,6 +76,7 @@ public Model(ConventionSet conventions, ModelDependencies? modelDependencies = n _modelFinalizedConventions = conventions.ModelFinalizedConventions; Builder = builder; Configuration = modelConfiguration; + ModelId = Guid.NewGuid(); dispatcher.OnModelInitialized(builder); } @@ -459,7 +461,7 @@ public virtual IEnumerable FindEntityTypes(Type type) /// 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 Guid ModelId { get; set; } = Guid.NewGuid(); + public virtual Guid ModelId { get; set; } /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to diff --git a/test/EFCore.Cosmos.Tests/ModelBuilding/CosmosModelBuilderGenericTest.cs b/test/EFCore.Cosmos.Tests/ModelBuilding/CosmosModelBuilderGenericTest.cs index 48c428d3bd8..0dd3ed80234 100644 --- a/test/EFCore.Cosmos.Tests/ModelBuilding/CosmosModelBuilderGenericTest.cs +++ b/test/EFCore.Cosmos.Tests/ModelBuilding/CosmosModelBuilderGenericTest.cs @@ -9,8 +9,13 @@ namespace Microsoft.EntityFrameworkCore.ModelBuilding; public class CosmosModelBuilderGenericTest : ModelBuilderGenericTest { - public class CosmosGenericNonRelationship : GenericNonRelationship + public class CosmosGenericNonRelationship : GenericNonRelationship, IClassFixture { + public CosmosGenericNonRelationship(CosmosModelBuilderFixture fixture) + : base(fixture) + { + } + public override void Can_set_composite_key_for_primitive_collection_on_an_entity_with_fields() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(EntityWithFields), "CollectionCompanyId"), @@ -433,8 +438,13 @@ protected override TestModelBuilder CreateModelBuilder(Action CreateTestModelBuilder(CosmosTestHelpers.Instance, configure); } - public class CosmosGenericComplexType : GenericComplexType + public class CosmosGenericComplexType : GenericComplexType, IClassFixture { + public CosmosGenericComplexType(CosmosModelBuilderFixture fixture) + : base(fixture) + { + } + public override void Access_mode_can_be_overridden_at_entity_and_property_levels() => Assert.Equal( CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Down"), @@ -766,8 +776,13 @@ protected override TestModelBuilder CreateModelBuilder(Action CreateTestModelBuilder(CosmosTestHelpers.Instance, configure); } - public class CosmosGenericInheritance : GenericInheritance + public class CosmosGenericInheritance : GenericInheritance, IClassFixture { + public CosmosGenericInheritance(CosmosModelBuilderFixture fixture) + : base(fixture) + { + } + public override void Base_type_can_be_discovered_after_creating_foreign_keys_on_derived() { var mb = CreateModelBuilder(); @@ -795,8 +810,13 @@ protected override TestModelBuilder CreateModelBuilder(Action CreateTestModelBuilder(CosmosTestHelpers.Instance, configure); } - public class CosmosGenericOneToMany : GenericOneToMany + public class CosmosGenericOneToMany : GenericOneToMany, IClassFixture { + public CosmosGenericOneToMany(CosmosModelBuilderFixture fixture) + : base(fixture) + { + } + public override void Navigation_to_shared_type_is_not_discovered_by_convention() { var modelBuilder = CreateModelBuilder(); @@ -818,14 +838,24 @@ protected override TestModelBuilder CreateModelBuilder(Action CreateTestModelBuilder(CosmosTestHelpers.Instance, configure); } - public class CosmosGenericManyToOne : GenericManyToOne + public class CosmosGenericManyToOne : GenericManyToOne, IClassFixture { + public CosmosGenericManyToOne(CosmosModelBuilderFixture fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateModelBuilder(Action configure = null) => CreateTestModelBuilder(CosmosTestHelpers.Instance, configure); } - public class CosmosGenericOneToOne : GenericOneToOne + public class CosmosGenericOneToOne : GenericOneToOne, IClassFixture { + public CosmosGenericOneToOne(CosmosModelBuilderFixture fixture) + : base(fixture) + { + } + public override void Navigation_to_shared_type_is_not_discovered_by_convention() { var modelBuilder = CreateModelBuilder(); @@ -847,8 +877,13 @@ protected override TestModelBuilder CreateModelBuilder(Action CreateTestModelBuilder(CosmosTestHelpers.Instance, configure); } - public class CosmosGenericManyToMany : GenericManyToMany + public class CosmosGenericManyToMany : GenericManyToMany, IClassFixture { + public CosmosGenericManyToMany(CosmosModelBuilderFixture fixture) + : base(fixture) + { + } + [ConditionalFact] public virtual void Can_use_shared_type_as_join_entity_with_partition_keys() { @@ -1002,8 +1037,13 @@ protected override TestModelBuilder CreateModelBuilder(Action CreateTestModelBuilder(CosmosTestHelpers.Instance, configure); } - public class CosmosGenericOwnedTypes : GenericOwnedTypes + public class CosmosGenericOwnedTypes : GenericOwnedTypes, IClassFixture { + public CosmosGenericOwnedTypes(CosmosModelBuilderFixture fixture) + : base(fixture) + { + } + public override void Deriving_from_owned_type_throws() // On Cosmos the base type starts as owned => Assert.Contains( @@ -1048,4 +1088,19 @@ public virtual void Reference_type_is_discovered_as_owned() protected override TestModelBuilder CreateModelBuilder(Action configure = null) => CreateTestModelBuilder(CosmosTestHelpers.Instance, 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); + } + } } diff --git a/test/EFCore.InMemory.Tests/ModelBuilding/InMemoryModelBuilderGenericTest.cs b/test/EFCore.InMemory.Tests/ModelBuilding/InMemoryModelBuilderGenericTest.cs index 291cb87beb0..44a02ef57c5 100644 --- a/test/EFCore.InMemory.Tests/ModelBuilding/InMemoryModelBuilderGenericTest.cs +++ b/test/EFCore.InMemory.Tests/ModelBuilding/InMemoryModelBuilderGenericTest.cs @@ -9,26 +9,46 @@ namespace Microsoft.EntityFrameworkCore.ModelBuilding; public class InMemoryModelBuilderGenericTest : ModelBuilderGenericTest { - public class InMemoryGenericNonRelationship : GenericNonRelationship + public class InMemoryGenericNonRelationship : GenericNonRelationship, IClassFixture { + public InMemoryGenericNonRelationship(InMemoryModelBuilderFixture fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateModelBuilder(Action configure = null) => CreateTestModelBuilder(InMemoryTestHelpers.Instance, configure); } - public class InMemoryGenericComplexTypeTestBase : GenericComplexType + public class InMemoryGenericComplexTypeTestBase : GenericComplexType, IClassFixture { + public InMemoryGenericComplexTypeTestBase(InMemoryModelBuilderFixture fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateModelBuilder(Action configure = null) => CreateTestModelBuilder(InMemoryTestHelpers.Instance, configure); } - public class InMemoryGenericInheritance : GenericInheritance + public class InMemoryGenericInheritance : GenericInheritance, IClassFixture { + public InMemoryGenericInheritance(InMemoryModelBuilderFixture fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateModelBuilder(Action configure = null) => CreateTestModelBuilder(InMemoryTestHelpers.Instance, configure); } - public class InMemoryGenericOneToMany : GenericOneToMany + public class InMemoryGenericOneToMany : GenericOneToMany, IClassFixture { + public InMemoryGenericOneToMany(InMemoryModelBuilderFixture fixture) + : base(fixture) + { + } + [ConditionalFact] // Issue #3376 public virtual void Can_use_self_referencing_overlapping_FK_PK() { @@ -145,14 +165,24 @@ protected override TestModelBuilder CreateModelBuilder(Action CreateTestModelBuilder(InMemoryTestHelpers.Instance, configure); } - public class InMemoryGenericManyToOne : GenericManyToOne + public class InMemoryGenericManyToOne : GenericManyToOne, IClassFixture { + public InMemoryGenericManyToOne(InMemoryModelBuilderFixture fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateModelBuilder(Action configure = null) => CreateTestModelBuilder(InMemoryTestHelpers.Instance, configure); } - public class InMemoryGenericOneToOne : GenericOneToOne + public class InMemoryGenericOneToOne : GenericOneToOne, IClassFixture { + public InMemoryGenericOneToOne(InMemoryModelBuilderFixture fixture) + : base(fixture) + { + } + [ConditionalFact] public virtual void Can_use_self_referencing_overlapping_FK_PK() { @@ -236,9 +266,18 @@ protected override TestModelBuilder CreateModelBuilder(Action CreateTestModelBuilder(InMemoryTestHelpers.Instance, configure); } - public class InMemoryGenericOwnedTypes : GenericOwnedTypes + public class InMemoryGenericOwnedTypes : GenericOwnedTypes, IClassFixture { + public InMemoryGenericOwnedTypes(InMemoryModelBuilderFixture fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateModelBuilder(Action configure = null) => CreateTestModelBuilder(InMemoryTestHelpers.Instance, configure); } + + public class InMemoryModelBuilderFixture : ModelBuilderFixtureBase + { + } } diff --git a/test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs b/test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs index cfb5a489bcc..c5b569922bf 100644 --- a/test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs +++ b/test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs @@ -3164,8 +3164,8 @@ public static void AssertEqual(IRelationalModel expectedModel, IRelationalModel expectedModel.StoredProcedures.ZipAssert(actualModel.StoredProcedures, AssertEqual); Assert.Equal(((RelationalModel)expectedModel).IsReadOnly, ((RelationalModel)actualModel).IsReadOnly); - Assert.Equal(expectedModel.GetAnnotations(), actualModel.GetAnnotations(), AnnotationComparer.Instance); - Assert.Equal(expectedModel.GetRuntimeAnnotations(), actualModel.GetRuntimeAnnotations(), AnnotationComparer.Instance); + Assert.Equal(expectedModel.GetAnnotations(), actualModel.GetAnnotations(), TestAnnotationComparer.Instance); + Assert.Equal(expectedModel.GetRuntimeAnnotations(), actualModel.GetRuntimeAnnotations(), TestAnnotationComparer.Instance); } public static void AssertEqualBase(ITableBase expected, ITableBase actual) @@ -3191,8 +3191,8 @@ public static void AssertEqualBase(ITableBase expected, ITableBase actual) var actualEntityType = actual.ComplexTypeMappings.Single(m => m.TypeBase.Name == expectedEntityType.Name).TypeBase; } - Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), AnnotationComparer.Instance); - Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), AnnotationComparer.Instance); + Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), TestAnnotationComparer.Instance); + Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), TestAnnotationComparer.Instance); } public static void AssertEqual(ITableBase expected, ITableBase actual) @@ -3213,8 +3213,8 @@ public static void AssertEqualBase(ITableMappingBase expected, ITableMappingBase Assert.Equal(expected.IsSharedTablePrincipal, actual.IsSharedTablePrincipal); Assert.Equal(expected.IsSplitEntityTypePrincipal, actual.IsSplitEntityTypePrincipal); - Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), AnnotationComparer.Instance); - Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), AnnotationComparer.Instance); + Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), TestAnnotationComparer.Instance); + Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), TestAnnotationComparer.Instance); } public static void AssertEqual(ITableMappingBase expected, ITableMappingBase actual) @@ -3232,8 +3232,8 @@ public static void AssertEqualBase(IColumnBase expected, IColumnBase actual) Assert.Equal(expected.StoreType, actual.StoreType); Assert.Equal(expected.StoreTypeMapping.StoreType, actual.StoreTypeMapping.StoreType); - Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), AnnotationComparer.Instance); - Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), AnnotationComparer.Instance); + Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), TestAnnotationComparer.Instance); + Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), TestAnnotationComparer.Instance); } public static void AssertEqual(IColumnBase expected, IColumnBase actual) @@ -3251,8 +3251,8 @@ public static void AssertEqualBase(IColumnMappingBase expected, IColumnMappingBa Assert.Equal(expected.Property.Name, actual.Property.Name); Assert.Equal(expected.TypeMapping.StoreType, actual.TypeMapping.StoreType); - Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), AnnotationComparer.Instance); - Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), AnnotationComparer.Instance); + Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), TestAnnotationComparer.Instance); + Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), TestAnnotationComparer.Instance); } public static void AssertEqual(IColumnMappingBase expected, IColumnMappingBase actual) @@ -3313,8 +3313,8 @@ public static void AssertEqual(ITableIndex expected, ITableIndex actual) 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(), AnnotationComparer.Instance); - Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), AnnotationComparer.Instance); + Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), TestAnnotationComparer.Instance); + Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), TestAnnotationComparer.Instance); } public static void AssertEqual(IForeignKeyConstraint expected, IForeignKeyConstraint actual) @@ -3330,8 +3330,8 @@ public static void AssertEqual(IForeignKeyConstraint expected, IForeignKeyConstr 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(), AnnotationComparer.Instance); - Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), AnnotationComparer.Instance); + Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), TestAnnotationComparer.Instance); + Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), TestAnnotationComparer.Instance); } public static void AssertEqual(IUniqueConstraint expected, IUniqueConstraint actual) @@ -3344,8 +3344,8 @@ public static void AssertEqual(IUniqueConstraint expected, IUniqueConstraint act 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(), AnnotationComparer.Instance); - Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), AnnotationComparer.Instance); + Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), TestAnnotationComparer.Instance); + Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), TestAnnotationComparer.Instance); } public static void AssertEqual(ITrigger expected, ITrigger actual) @@ -3354,8 +3354,8 @@ public static void AssertEqual(ITrigger expected, ITrigger actual) Assert.Equal(expected.GetTableName(), actual.GetTableName()); Assert.Equal(expected.GetTableSchema(), actual.GetTableSchema()); - Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), AnnotationComparer.Instance); - Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), AnnotationComparer.Instance); + Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), TestAnnotationComparer.Instance); + Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), TestAnnotationComparer.Instance); } public static void AssertEqual(IView expected, IView actual) @@ -3453,8 +3453,8 @@ public static void AssertEqual(IFunctionMapping expected, IFunctionMapping actua Assert.Equal(expected.IsDefaultFunctionMapping, actual.IsDefaultFunctionMapping); Assert.Contains(expected.DbFunction.Name, actual.DbFunction.Name); - Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), AnnotationComparer.Instance); - Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), AnnotationComparer.Instance); + Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), TestAnnotationComparer.Instance); + Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), TestAnnotationComparer.Instance); } public static void AssertEqual(IFunctionColumn expected, IFunctionColumn actual) @@ -3480,8 +3480,8 @@ public static void AssertEqual(IStoreFunctionParameter expected, IStoreFunctionP 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(), AnnotationComparer.Instance); - Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), AnnotationComparer.Instance); + Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), TestAnnotationComparer.Instance); + Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), TestAnnotationComparer.Instance); } public static void AssertEqual(IStoreStoredProcedure expected, IStoreStoredProcedure actual) @@ -3524,8 +3524,8 @@ public static void AssertEqual(IStoredProcedureMapping expected, IStoredProcedur Assert.Contains(expected.TableMapping?.Table.SchemaQualifiedName, actual.TableMapping?.Table.SchemaQualifiedName); - Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), AnnotationComparer.Instance); - Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), AnnotationComparer.Instance); + Assert.Equal(expected.GetAnnotations(), actual.GetAnnotations(), TestAnnotationComparer.Instance); + Assert.Equal(expected.GetRuntimeAnnotations(), actual.GetRuntimeAnnotations(), TestAnnotationComparer.Instance); } public static void AssertEqual(IStoreStoredProcedureResultColumn expected, IStoreStoredProcedureResultColumn actual) diff --git a/test/EFCore.Relational.Tests/ModelBuilding/RelationalModelBuilderTest.cs b/test/EFCore.Relational.Tests/ModelBuilding/RelationalModelBuilderTest.cs index d0fb6786d21..919dfb2992a 100644 --- a/test/EFCore.Relational.Tests/ModelBuilding/RelationalModelBuilderTest.cs +++ b/test/EFCore.Relational.Tests/ModelBuilding/RelationalModelBuilderTest.cs @@ -12,6 +12,11 @@ public class RelationalModelBuilderTest : ModelBuilderTest { public abstract class RelationalNonRelationshipTestBase : NonRelationshipTestBase { + public RelationalNonRelationshipTestBase(RelationalModelBuilderFixture fixture) + : base(fixture) + { + } + [ConditionalFact] public virtual void Can_use_table_splitting() { @@ -341,6 +346,11 @@ public virtual void Configuring_direction_on_RowsAffectedParameter_throws() public abstract class RelationalComplexTypeTestBase : ComplexTypeTestBase { + public RelationalComplexTypeTestBase(RelationalModelBuilderFixture fixture) + : base(fixture) + { + } + [ConditionalFact] public virtual void Can_use_TPH() { @@ -649,6 +659,11 @@ public virtual void Configuring_direction_on_RowsAffectedParameter_throws() public abstract class RelationalInheritanceTestBase : InheritanceTestBase { + public RelationalInheritanceTestBase(RelationalModelBuilderFixture fixture) + : base(fixture) + { + } + [ConditionalFact] public virtual void Can_use_table_splitting() { @@ -693,22 +708,43 @@ public virtual void Can_use_table_splitting() public abstract class RelationalOneToManyTestBase : OneToManyTestBase { + public RelationalOneToManyTestBase(RelationalModelBuilderFixture fixture) + : base(fixture) + { + } } public abstract class RelationalManyToOneTestBase : ManyToOneTestBase { + public RelationalManyToOneTestBase(RelationalModelBuilderFixture fixture) + : base(fixture) + { + } } public abstract class RelationalOneToOneTestBase : OneToOneTestBase { + public RelationalOneToOneTestBase(RelationalModelBuilderFixture fixture) + : base(fixture) + { + } } public abstract class RelationalManyToManyTestBase : ManyToManyTestBase { + public RelationalManyToManyTestBase(RelationalModelBuilderFixture fixture) + : base(fixture) + { + } } public abstract class RelationalOwnedTypesTestBase : OwnedTypesTestBase { + public RelationalOwnedTypesTestBase(RelationalModelBuilderFixture fixture) + : base(fixture) + { + } + [ConditionalFact] public virtual void Can_use_table_splitting_with_owned_reference() { @@ -947,6 +983,7 @@ public virtual void Can_use_sproc_mapping_with_owned_reference() Assert.Null(bookOwnership2.DeclaringEntityType.GetDeleteStoredProcedure()); } #nullable disable + protected class JsonEntity { public int Id { get; set; } @@ -1012,6 +1049,10 @@ protected class JsonEntityWithNesting #nullable enable } + public class RelationalModelBuilderFixture : ModelBuilderFixtureBase + { + } + public abstract class TestTableBuilder where TEntity : class { diff --git a/test/EFCore.Specification.Tests/EFCore.Specification.Tests.csproj b/test/EFCore.Specification.Tests/EFCore.Specification.Tests.csproj index 291c1d3344e..fdf140e1944 100644 --- a/test/EFCore.Specification.Tests/EFCore.Specification.Tests.csproj +++ b/test/EFCore.Specification.Tests/EFCore.Specification.Tests.csproj @@ -54,6 +54,7 @@ + diff --git a/test/EFCore.Specification.Tests/TestUtilities/ForeignKeyStrictComparer.cs b/test/EFCore.Specification.Tests/TestUtilities/ForeignKeyStrictComparer.cs deleted file mode 100644 index 3329835b1ca..00000000000 --- a/test/EFCore.Specification.Tests/TestUtilities/ForeignKeyStrictComparer.cs +++ /dev/null @@ -1,40 +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 class ForeignKeyStrictComparer : IEqualityComparer, IComparer -{ - private readonly bool _compareAnnotations; - private readonly bool _compareNavigations; - - public ForeignKeyStrictComparer(bool compareAnnotations = true, bool compareNavigations = true) - { - _compareAnnotations = compareAnnotations; - _compareNavigations = compareNavigations; - } - - public int Compare(IReadOnlyForeignKey x, IReadOnlyForeignKey y) - => ForeignKeyComparer.Instance.Compare(x, y); - - public bool Equals(IReadOnlyForeignKey x, IReadOnlyForeignKey y) - { - if (x == null) - { - return y == null; - } - - return y == null - ? false - : ForeignKeyComparer.Instance.Equals(x, y) - && (x.IsUnique == y.IsUnique) - && (x.IsRequired == y.IsRequired) - && (!_compareNavigations - || (new NavigationComparer(_compareAnnotations).Equals(x.DependentToPrincipal, y.DependentToPrincipal) - && new NavigationComparer(_compareAnnotations).Equals(x.PrincipalToDependent, y.PrincipalToDependent))) - && (!_compareAnnotations || x.GetAnnotations().SequenceEqual(y.GetAnnotations(), AnnotationComparer.Instance)); - } - - public int GetHashCode(IReadOnlyForeignKey obj) - => ForeignKeyComparer.Instance.GetHashCode(obj); -} diff --git a/test/EFCore.Specification.Tests/TestUtilities/MetadataExtensions.cs b/test/EFCore.Specification.Tests/TestUtilities/MetadataExtensions.cs index a3ceeb18820..b9b0bb96db8 100644 --- a/test/EFCore.Specification.Tests/TestUtilities/MetadataExtensions.cs +++ b/test/EFCore.Specification.Tests/TestUtilities/MetadataExtensions.cs @@ -23,133 +23,4 @@ public static void ForEach(this IEnumerable @this, Action action) action(item); } } - - public static IReadOnlyModel Clone(this IReadOnlyModel model) - { - IMutableModel modelClone = new Model(); - var clonedEntityTypes = new Dictionary(); - foreach (var entityType in model.GetEntityTypes()) - { - var clrType = entityType.ClrType; - var clonedEntityType = clrType == null - ? modelClone.AddEntityType(entityType.Name) - : modelClone.AddEntityType(clrType); - - clonedEntityTypes.Add(entityType, clonedEntityType); - } - - foreach (var clonedEntityType in clonedEntityTypes) - { - if (clonedEntityType.Key.BaseType != null) - { - clonedEntityType.Value.BaseType = clonedEntityTypes[clonedEntityType.Key.BaseType]; - } - } - - foreach (var clonedEntityType in clonedEntityTypes) - { - CloneProperties(clonedEntityType.Key, clonedEntityType.Value); - } - - foreach (var clonedEntityType in clonedEntityTypes) - { - CloneIndexes(clonedEntityType.Key, clonedEntityType.Value); - } - - foreach (var clonedEntityType in clonedEntityTypes) - { - CloneKeys(clonedEntityType.Key, clonedEntityType.Value); - } - - foreach (var clonedEntityType in clonedEntityTypes) - { - CloneForeignKeys(clonedEntityType.Key, clonedEntityType.Value); - } - - foreach (var clonedEntityType in clonedEntityTypes) - { - CloneNavigations(clonedEntityType.Key, clonedEntityType.Value); - } - - return modelClone; - } - - private static void CloneProperties(IReadOnlyEntityType sourceEntityType, IMutableEntityType targetEntityType) - { - foreach (var property in sourceEntityType.GetDeclaredProperties()) - { - var clonedProperty = targetEntityType.AddProperty(property.Name, property.ClrType); - clonedProperty.IsNullable = property.IsNullable; - clonedProperty.IsConcurrencyToken = property.IsConcurrencyToken; - clonedProperty.ValueGenerated = property.ValueGenerated; - clonedProperty.SetBeforeSaveBehavior(property.GetBeforeSaveBehavior()); - clonedProperty.SetAfterSaveBehavior(property.GetAfterSaveBehavior()); - property.GetAnnotations().ForEach(annotation => clonedProperty[annotation.Name] = annotation.Value); - } - } - - private static void CloneKeys(IReadOnlyEntityType sourceEntityType, IMutableEntityType targetEntityType) - { - foreach (var key in sourceEntityType.GetDeclaredKeys()) - { - var clonedKey = targetEntityType.AddKey( - key.Properties.Select(p => targetEntityType.FindProperty(p.Name)).ToList()); - if (key.IsPrimaryKey()) - { - targetEntityType.SetPrimaryKey(clonedKey.Properties); - } - - key.GetAnnotations().ForEach(annotation => clonedKey[annotation.Name] = annotation.Value); - } - } - - private static void CloneIndexes(IReadOnlyEntityType sourceEntityType, IMutableEntityType targetEntityType) - { - foreach (var index in sourceEntityType.GetDeclaredIndexes()) - { - var clonedIndex = targetEntityType.AddIndex( - index.Properties.Select(p => targetEntityType.FindProperty(p.Name)).ToList()); - clonedIndex.IsUnique = index.IsUnique; - index.GetAnnotations().ForEach(annotation => clonedIndex[annotation.Name] = annotation.Value); - } - } - - private static void CloneForeignKeys(IReadOnlyEntityType sourceEntityType, IMutableEntityType targetEntityType) - { - foreach (var foreignKey in sourceEntityType.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); - clonedForeignKey.IsUnique = foreignKey.IsUnique; - clonedForeignKey.IsRequired = foreignKey.IsRequired; - foreignKey.GetAnnotations().ForEach(annotation => clonedForeignKey[annotation.Name] = annotation.Value); - } - } - - private static void CloneNavigations(IReadOnlyEntityType sourceEntityType, IMutableEntityType targetEntityType) - { - foreach (var navigation in sourceEntityType.GetDeclaredNavigations()) - { - var targetDependentEntityType = targetEntityType.Model.FindEntityType(navigation.ForeignKey.DeclaringEntityType.Name); - var targetPrincipalEntityType = targetEntityType.Model.FindEntityType(navigation.ForeignKey.PrincipalEntityType.Name); - var targetForeignKey = targetDependentEntityType.FindForeignKey( - navigation.ForeignKey.Properties.Select(p => targetDependentEntityType.FindProperty(p.Name)).ToList(), - targetPrincipalEntityType.FindKey( - navigation.ForeignKey.PrincipalKey.Properties.Select( - p => targetPrincipalEntityType.FindProperty(p.Name)).ToList()), - targetPrincipalEntityType); - var clonedNavigation = navigation.IsOnDependent - ? (navigation.GetIdentifyingMemberInfo() != null - ? targetForeignKey.SetDependentToPrincipal(navigation.GetIdentifyingMemberInfo()) - : targetForeignKey.SetDependentToPrincipal(navigation.Name)) - : (navigation.GetIdentifyingMemberInfo() != null - ? targetForeignKey.SetPrincipalToDependent(navigation.GetIdentifyingMemberInfo()) - : targetForeignKey.SetPrincipalToDependent(navigation.Name)); - navigation.GetAnnotations().ForEach(annotation => clonedNavigation[annotation.Name] = annotation.Value); - } - } } diff --git a/test/EFCore.Specification.Tests/TestUtilities/NavigationComparer.cs b/test/EFCore.Specification.Tests/TestUtilities/NavigationComparer.cs deleted file mode 100644 index eb4707da5de..00000000000 --- a/test/EFCore.Specification.Tests/TestUtilities/NavigationComparer.cs +++ /dev/null @@ -1,33 +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 class NavigationComparer : IEqualityComparer, IComparer -{ - private readonly bool _compareAnnotations; - - public NavigationComparer(bool compareAnnotations = true) - { - _compareAnnotations = compareAnnotations; - } - - public int Compare(IReadOnlyNavigation x, IReadOnlyNavigation y) - => StringComparer.Ordinal.Compare(x.Name, y.Name); - - public bool Equals(IReadOnlyNavigation x, IReadOnlyNavigation y) - { - if (x == null) - { - return y == null; - } - - return y == null - ? false - : x.Name == y.Name - && (!_compareAnnotations || x.GetAnnotations().SequenceEqual(y.GetAnnotations(), AnnotationComparer.Instance)); - } - - public int GetHashCode(IReadOnlyNavigation obj) - => obj.Name.GetHashCode(); -} diff --git a/test/EFCore.Specification.Tests/TestUtilities/PropertyComparer.cs b/test/EFCore.Specification.Tests/TestUtilities/PropertyComparer.cs deleted file mode 100644 index fae9745cec6..00000000000 --- a/test/EFCore.Specification.Tests/TestUtilities/PropertyComparer.cs +++ /dev/null @@ -1,40 +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 class PropertyComparer : IEqualityComparer, IComparer -{ - private readonly bool _compareAnnotations; - - public PropertyComparer(bool compareAnnotations = true) - { - _compareAnnotations = compareAnnotations; - } - - public int Compare(IReadOnlyProperty x, IReadOnlyProperty y) - => StringComparer.Ordinal.Compare(x.Name, y.Name); - - public bool Equals(IReadOnlyProperty x, IReadOnlyProperty y) - { - if (x == null) - { - return y == null; - } - - return y == null - ? false - : x.Name == y.Name - && x.ClrType == y.ClrType - && x.IsShadowProperty() == y.IsShadowProperty() - && x.IsNullable == y.IsNullable - && x.IsConcurrencyToken == y.IsConcurrencyToken - && x.ValueGenerated == y.ValueGenerated - && x.GetBeforeSaveBehavior() == y.GetBeforeSaveBehavior() - && x.GetAfterSaveBehavior() == y.GetAfterSaveBehavior() - && (!_compareAnnotations || x.GetAnnotations().SequenceEqual(y.GetAnnotations(), AnnotationComparer.Instance)); - } - - public int GetHashCode(IReadOnlyProperty obj) - => obj.Name.GetHashCode(); -} diff --git a/test/EFCore.Specification.Tests/TestUtilities/AnnotationComparer.cs b/test/EFCore.Specification.Tests/TestUtilities/TestAnnotationComparer.cs similarity index 81% rename from test/EFCore.Specification.Tests/TestUtilities/AnnotationComparer.cs rename to test/EFCore.Specification.Tests/TestUtilities/TestAnnotationComparer.cs index bdc460e5ba1..8b546c4c520 100644 --- a/test/EFCore.Specification.Tests/TestUtilities/AnnotationComparer.cs +++ b/test/EFCore.Specification.Tests/TestUtilities/TestAnnotationComparer.cs @@ -6,11 +6,11 @@ // ReSharper disable PossibleNullReferenceException namespace Microsoft.EntityFrameworkCore.TestUtilities; -public class AnnotationComparer : IEqualityComparer, IComparer +public class TestAnnotationComparer : IEqualityComparer, IComparer { - public static readonly AnnotationComparer Instance = new(); + public static readonly TestAnnotationComparer Instance = new(); - private AnnotationComparer() + private TestAnnotationComparer() { } diff --git a/test/EFCore.Specification.Tests/TestUtilities/TestIndexComparer.cs b/test/EFCore.Specification.Tests/TestUtilities/TestIndexComparer.cs deleted file mode 100644 index 75ff2397f1a..00000000000 --- a/test/EFCore.Specification.Tests/TestUtilities/TestIndexComparer.cs +++ /dev/null @@ -1,36 +0,0 @@ -// 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 TestIndexComparer : IEqualityComparer, IComparer -{ - private readonly bool _compareAnnotations; - - public TestIndexComparer(bool compareAnnotations = true) - { - _compareAnnotations = compareAnnotations; - } - - public int Compare(IReadOnlyIndex x, IReadOnlyIndex y) - => PropertyListComparer.Instance.Compare(x.Properties, y.Properties); - - public bool Equals(IReadOnlyIndex x, IReadOnlyIndex y) - { - if (x == null) - { - return y == null; - } - - return y == null - ? false - : PropertyListComparer.Instance.Equals(x.Properties, y.Properties) - && x.IsUnique == y.IsUnique - && (!_compareAnnotations || x.GetAnnotations().SequenceEqual(y.GetAnnotations(), AnnotationComparer.Instance)); - } - - public int GetHashCode(IReadOnlyIndex obj) - => PropertyListComparer.Instance.GetHashCode(obj.Properties); -} diff --git a/test/EFCore.Specification.Tests/TestUtilities/TestKeyComparer.cs b/test/EFCore.Specification.Tests/TestUtilities/TestKeyComparer.cs deleted file mode 100644 index a2e1b21e60e..00000000000 --- a/test/EFCore.Specification.Tests/TestUtilities/TestKeyComparer.cs +++ /dev/null @@ -1,35 +0,0 @@ -// 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 TestKeyComparer : IEqualityComparer, IComparer -{ - private readonly bool _compareAnnotations; - - public TestKeyComparer(bool compareAnnotations = true) - { - _compareAnnotations = compareAnnotations; - } - - public int Compare(IReadOnlyKey x, IReadOnlyKey y) - => PropertyListComparer.Instance.Compare(x.Properties, y.Properties); - - public bool Equals(IReadOnlyKey x, IReadOnlyKey y) - { - if (x == null) - { - return y == null; - } - - return y == null - ? false - : PropertyListComparer.Instance.Equals(x.Properties, y.Properties) - && (!_compareAnnotations || x.GetAnnotations().SequenceEqual(y.GetAnnotations(), AnnotationComparer.Instance)); - } - - public int GetHashCode(IReadOnlyKey obj) - => PropertyListComparer.Instance.GetHashCode(obj.Properties); -} diff --git a/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderGenericTest.cs b/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderGenericTest.cs index a49a0be0595..f5017e99315 100644 --- a/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderGenericTest.cs +++ b/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderGenericTest.cs @@ -8,64 +8,104 @@ namespace Microsoft.EntityFrameworkCore.ModelBuilding; public class SqlServerModelBuilderGenericTest : SqlServerModelBuilderTestBase { - public class SqlServerGenericNonRelationship : SqlServerNonRelationship + public class SqlServerGenericNonRelationship : SqlServerNonRelationship, IClassFixture { + public SqlServerGenericNonRelationship(SqlServerModelBuilderFixture fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) => new ModelBuilderGenericTest.GenericTestModelBuilder(testHelpers, configure); } - public class SqlServerGenericComplexType : SqlServerComplexType + public class SqlServerGenericComplexType : SqlServerComplexType, IClassFixture { + public SqlServerGenericComplexType(SqlServerModelBuilderFixture fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) => new ModelBuilderGenericTest.GenericTestModelBuilder(testHelpers, configure); } - public class SqlServerGenericInheritance : SqlServerInheritance + public class SqlServerGenericInheritance : SqlServerInheritance, IClassFixture { + public SqlServerGenericInheritance(SqlServerModelBuilderFixture fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) => new ModelBuilderGenericTest.GenericTestModelBuilder(testHelpers, configure); } - public class SqlServerGenericOneToMany : SqlServerOneToMany + public class SqlServerGenericOneToMany : SqlServerOneToMany, IClassFixture { + public SqlServerGenericOneToMany(SqlServerModelBuilderFixture fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) => new ModelBuilderGenericTest.GenericTestModelBuilder(testHelpers, configure); } - public class SqlServerGenericManyToOne : SqlServerManyToOne + public class SqlServerGenericManyToOne : SqlServerManyToOne, IClassFixture { + public SqlServerGenericManyToOne(SqlServerModelBuilderFixture fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) => new ModelBuilderGenericTest.GenericTestModelBuilder(testHelpers, configure); } - public class SqlServerGenericOneToOne : SqlServerOneToOne + public class SqlServerGenericOneToOne : SqlServerOneToOne, IClassFixture { + public SqlServerGenericOneToOne(SqlServerModelBuilderFixture fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) => new ModelBuilderGenericTest.GenericTestModelBuilder(testHelpers, configure); } - public class SqlServerGenericManyToMany : SqlServerManyToMany + public class SqlServerGenericManyToMany : SqlServerManyToMany, IClassFixture { + public SqlServerGenericManyToMany(SqlServerModelBuilderFixture fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) => new ModelBuilderGenericTest.GenericTestModelBuilder(testHelpers, configure); } - public class SqlServerGenericOwnedTypes : SqlServerOwnedTypes + public class SqlServerGenericOwnedTypes : SqlServerOwnedTypes, IClassFixture { + public SqlServerGenericOwnedTypes(SqlServerModelBuilderFixture fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) diff --git a/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderNonGenericTest.cs b/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderNonGenericTest.cs index 37d8f51cea6..8597c0d254d 100644 --- a/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderNonGenericTest.cs +++ b/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderNonGenericTest.cs @@ -8,64 +8,104 @@ namespace Microsoft.EntityFrameworkCore.ModelBuilding; public class SqlServerModelBuilderNonGenericTest : SqlServerModelBuilderTestBase { - public class SqlServerNonGenericNonRelationship : SqlServerNonRelationship + 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 + 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 + 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 + 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 + 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 + 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 + 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 + public class SqlServerNonGenericOwnedTypes : SqlServerOwnedTypes, IClassFixture { + public SqlServerNonGenericOwnedTypes(SqlServerModelBuilderFixture fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) diff --git a/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderTestBase.cs b/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderTestBase.cs index eb9b87c1e52..33a81dcc794 100644 --- a/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderTestBase.cs +++ b/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderTestBase.cs @@ -10,8 +10,13 @@ namespace Microsoft.EntityFrameworkCore.ModelBuilding; public class SqlServerModelBuilderTestBase : RelationalModelBuilderTest { - public abstract class SqlServerNonRelationship : RelationalNonRelationshipTestBase + public abstract class SqlServerNonRelationship : RelationalNonRelationshipTestBase, IClassFixture { + public SqlServerNonRelationship(SqlServerModelBuilderFixture fixture) + : base(fixture) + { + } + [ConditionalFact] public virtual void Index_has_a_filter_if_nonclustered_unique_with_nullable_properties() { @@ -302,14 +307,24 @@ protected override TestModelBuilder CreateModelBuilder(Action CreateTestModelBuilder(SqlServerTestHelpers.Instance, configure); } - public abstract class SqlServerComplexType : RelationalComplexTypeTestBase + public abstract class SqlServerComplexType : RelationalComplexTypeTestBase, IClassFixture { + public SqlServerComplexType(SqlServerModelBuilderFixture fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) => CreateTestModelBuilder(SqlServerTestHelpers.Instance, configure); } - public abstract class SqlServerInheritance : RelationalInheritanceTestBase + public abstract class SqlServerInheritance : RelationalInheritanceTestBase, IClassFixture { + public SqlServerInheritance(SqlServerModelBuilderFixture fixture) + : base(fixture) + { + } + [ConditionalFact] // #7240 public void Can_use_shadow_FK_that_collides_with_convention_shadow_FK_on_other_derived_type() { @@ -658,8 +673,13 @@ protected class DisjointChildSubclass2 : Child } } - public abstract class SqlServerOneToMany : RelationalOneToManyTestBase + public abstract class SqlServerOneToMany : RelationalOneToManyTestBase, IClassFixture { + public SqlServerOneToMany(SqlServerModelBuilderFixture fixture) + : base(fixture) + { + } + [ConditionalFact] public virtual void Shadow_foreign_keys_to_generic_types_have_terrible_names_that_should_not_change() { @@ -720,20 +740,35 @@ protected override TestModelBuilder CreateModelBuilder(Action CreateTestModelBuilder(SqlServerTestHelpers.Instance, configure); } - public abstract class SqlServerManyToOne : RelationalManyToOneTestBase + public abstract class SqlServerManyToOne : RelationalManyToOneTestBase, IClassFixture { + public SqlServerManyToOne(SqlServerModelBuilderFixture fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) => CreateTestModelBuilder(SqlServerTestHelpers.Instance, configure); } - public abstract class SqlServerOneToOne : RelationalOneToOneTestBase + public abstract class SqlServerOneToOne : RelationalOneToOneTestBase, IClassFixture { + public SqlServerOneToOne(SqlServerModelBuilderFixture fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) => CreateTestModelBuilder(SqlServerTestHelpers.Instance, configure); } - public abstract class SqlServerManyToMany : RelationalManyToManyTestBase + public abstract class SqlServerManyToMany : RelationalManyToManyTestBase, IClassFixture { + public SqlServerManyToMany(SqlServerModelBuilderFixture fixture) + : base(fixture) + { + } + [ConditionalFact] public virtual void Join_entity_type_uses_same_schema() { @@ -794,8 +829,13 @@ protected override TestModelBuilder CreateModelBuilder(Action CreateTestModelBuilder(SqlServerTestHelpers.Instance, configure); } - public abstract class SqlServerOwnedTypes : RelationalOwnedTypesTestBase + public abstract class SqlServerOwnedTypes : RelationalOwnedTypesTestBase, IClassFixture { + public SqlServerOwnedTypes(SqlServerModelBuilderFixture fixture) + : base(fixture) + { + } + [ConditionalFact] public virtual void Owned_types_use_table_splitting_by_default() { @@ -2190,6 +2230,10 @@ protected override TestModelBuilder CreateModelBuilder(Action CreateTestModelBuilder(SqlServerTestHelpers.Instance, configure); } + public class SqlServerModelBuilderFixture : RelationalModelBuilderFixture + { + } + public abstract class TestTemporalTableBuilder where TEntity : class { diff --git a/test/EFCore.Tests/ChangeTracking/Internal/InternalEntryEntrySubscriberTest.cs b/test/EFCore.Tests/ChangeTracking/Internal/InternalEntryEntrySubscriberTest.cs index dd5c4d46329..f536d8d4e20 100644 --- a/test/EFCore.Tests/ChangeTracking/Internal/InternalEntryEntrySubscriberTest.cs +++ b/test/EFCore.Tests/ChangeTracking/Internal/InternalEntryEntrySubscriberTest.cs @@ -263,7 +263,7 @@ public void Entry_handles_null_or_empty_string_in_INotifyPropertyChanging_and_IN entity.NotifyChanging(null); Assert.Equal( - ["Name", "RelatedCollection"], + new[] { "Name", "RelatedCollection" }, testListener.Changing.Select(e => e.Item2.Name).OrderBy(e => e).ToArray()); Assert.Empty(testListener.Changed); @@ -271,7 +271,7 @@ public void Entry_handles_null_or_empty_string_in_INotifyPropertyChanging_and_IN entity.NotifyChanged(""); Assert.Equal( - ["Name", "RelatedCollection"], + new[] { "Name", "RelatedCollection" }, testListener.Changed.Select(e => e.Item2.Name).OrderBy(e => e).ToArray()); } diff --git a/test/EFCore.Tests/ModelBuilding/ComplexTypeTestBase.cs b/test/EFCore.Tests/ModelBuilding/ComplexTypeTestBase.cs index d304ced8ee1..6bde46f363a 100644 --- a/test/EFCore.Tests/ModelBuilding/ComplexTypeTestBase.cs +++ b/test/EFCore.Tests/ModelBuilding/ComplexTypeTestBase.cs @@ -12,6 +12,11 @@ public abstract partial class ModelBuilderTest { public abstract class ComplexTypeTestBase : ModelBuilderTestBase { + public ComplexTypeTestBase(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + [ConditionalFact] public virtual void Can_set_complex_property_annotation() { @@ -475,6 +480,8 @@ public virtual void Access_mode_can_be_overridden_at_entity_and_property_levels( }); var model = modelBuilder.FinalizeModel(); + AssertEqual(modelBuilder.Model, model); + var entityType = model.FindEntityType(typeof(ComplexProperties))!; Assert.Equal(PropertyAccessMode.Field, model.GetPropertyAccessMode()); @@ -1593,6 +1600,7 @@ public virtual void Complex_properties_not_discovered_by_convention() }); var model = modelBuilder.FinalizeModel(); + AssertEqual(modelBuilder.Model, model); var customerType = model.FindEntityType(typeof(ComplexProperties))! .FindComplexProperty(nameof(ComplexProperties.Customer))!.ComplexType; diff --git a/test/EFCore.Tests/ModelBuilding/InheritanceTestBase.cs b/test/EFCore.Tests/ModelBuilding/InheritanceTestBase.cs index 5e5cd24dea5..70ad44cf5ee 100644 --- a/test/EFCore.Tests/ModelBuilding/InheritanceTestBase.cs +++ b/test/EFCore.Tests/ModelBuilding/InheritanceTestBase.cs @@ -12,6 +12,11 @@ public abstract partial class ModelBuilderTest { public abstract class InheritanceTestBase : ModelBuilderTestBase { + public InheritanceTestBase(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + [ConditionalFact] public virtual void Can_map_derived_types_first() { @@ -129,8 +134,8 @@ public virtual void Can_set_and_remove_base_type() modelBuilder.Entity().Ignore(b => b.Bun); Assert.Null(pickle.BaseType); - var pickleClone = modelBuilder.Model.Clone().FindEntityType(pickle.Name); - var initialProperties = pickleClone.GetProperties().Where(p => p.Name != "__jObject").ToList(); + var pickleClone = Clone(modelBuilder.Model).FindEntityType(pickle.Name); + var initialProperties = pickleClone.GetProperties().ToList(); var initialKeys = pickleClone.GetKeys().ToList(); var initialIndexes = pickleClone.GetIndexes().ToList(); var initialForeignKeys = pickleClone.GetForeignKeys().ToList(); @@ -142,35 +147,33 @@ public virtual void Can_set_and_remove_base_type() Assert.Same(typeof(Ingredient), pickle.BaseType.ClrType); - var actualProperties = pickle.GetProperties().Where(p => p.Name != "__jObject").ToList(); - AssertEqual( + var actualProperties = pickle.GetProperties(); + Fixture.AssertEqual( initialProperties.Where(p => p.Name != "Discriminator"), - actualProperties.Where(p => p.Name != "Discriminator"), - new PropertyComparer(compareAnnotations: false)); + actualProperties.Where(p => p.Name != "Discriminator")); - AssertEqual(initialKeys, pickle.GetKeys()); - AssertEqual(initialIndexes, pickle.GetIndexes()); - AssertEqual(initialForeignKeys, pickle.GetForeignKeys()); - AssertEqual(initialReferencingForeignKeys, pickle.GetReferencingForeignKeys()); + Fixture.AssertEqual(initialKeys, pickle.GetKeys()); + Fixture.AssertEqual(initialIndexes, pickle.GetIndexes()); + Fixture.AssertEqual(initialForeignKeys, pickle.GetForeignKeys()); + Fixture.AssertEqual(initialReferencingForeignKeys, pickle.GetReferencingForeignKeys()); pickleBuilder.HasBaseType(null); Assert.Null(pickle.BaseType); - actualProperties = pickle.GetProperties().Where(p => p.Name != "__jObject").ToList(); - AssertEqual(initialProperties, actualProperties, new PropertyComparer(compareAnnotations: false)); - AssertEqual(initialKeys, pickle.GetKeys()); - AssertEqual(initialIndexes, pickle.GetIndexes()); - AssertEqual(initialForeignKeys, pickle.GetForeignKeys()); - AssertEqual(initialReferencingForeignKeys, pickle.GetReferencingForeignKeys()); - - actualProperties = ingredient.GetProperties().Where(p => p.Name != "__jObject").ToList(); - AssertEqual( + 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()); + + actualProperties = ingredient.GetProperties(); + Fixture.AssertEqual( initialProperties.Where(p => p.Name != "Discriminator"), - actualProperties.Where(p => p.Name != "Discriminator"), - new PropertyComparer(compareAnnotations: false)); + actualProperties.Where(p => p.Name != "Discriminator")); - AssertEqual(initialKeys, ingredient.GetKeys()); - AssertEqual(initialIndexes, ingredient.GetIndexes()); + Fixture.AssertEqual(initialKeys, ingredient.GetKeys()); + Fixture.AssertEqual(initialIndexes, ingredient.GetIndexes()); Assert.Equal(initialForeignKeys.Count(), ingredient.GetForeignKeys().Count()); Assert.Equal(initialReferencingForeignKeys.Count(), ingredient.GetReferencingForeignKeys().Count()); } @@ -584,7 +587,7 @@ public virtual void Index_removed_when_covered_by_an_inherited_foreign_key() Assert.False(derivedDependentEntityType.GetDeclaredForeignKeys().Single().IsUnique); Assert.Empty(derivedDependentEntityType.GetDeclaredIndexes()); - var backOrderClone = modelBuilder.Model.Clone().FindEntityType(derivedDependentEntityType.Name); + var backOrderClone = Clone(modelBuilder.Model).FindEntityType(derivedDependentEntityType.Name); var initialProperties = backOrderClone.GetProperties().ToList(); var initialKeys = backOrderClone.GetKeys().ToList(); var initialIndexes = backOrderClone.GetIndexes().ToList(); @@ -603,10 +606,10 @@ public virtual void Index_removed_when_covered_by_an_inherited_foreign_key() Assert.Single(dependentEntityType.GetIndexes()); Assert.False(dependentEntityType.FindIndex(fk.Properties).IsUnique); - AssertEqual(initialProperties, derivedDependentEntityType.GetProperties(), new PropertyComparer(compareAnnotations: false)); - AssertEqual(initialKeys, derivedDependentEntityType.GetKeys()); - AssertEqual(initialIndexes, derivedDependentEntityType.GetIndexes()); - AssertEqual(initialForeignKeys, derivedDependentEntityType.GetForeignKeys()); + Fixture.AssertEqual(initialProperties, derivedDependentEntityType.GetProperties()); + Fixture.AssertEqual(initialKeys, derivedDependentEntityType.GetKeys()); + Fixture.AssertEqual(initialIndexes, derivedDependentEntityType.GetIndexes()); + Fixture.AssertEqual(initialForeignKeys, derivedDependentEntityType.GetForeignKeys()); principalEntityBuilder.HasOne().WithOne() .HasPrincipalKey( @@ -661,7 +664,7 @@ public virtual void Index_removed_when_covered_by_an_inherited_index() Assert.False(derivedDependentEntityType.GetDeclaredForeignKeys().Single().IsUnique); Assert.Empty(derivedDependentEntityType.GetDeclaredIndexes()); - var backOrderClone = modelBuilder.Model.Clone().FindEntityType(derivedDependentEntityType.Name); + var backOrderClone = Clone(modelBuilder.Model).FindEntityType(derivedDependentEntityType.Name); var initialProperties = backOrderClone.GetProperties().ToList(); var initialKeys = backOrderClone.GetKeys().ToList(); var initialIndexes = backOrderClone.GetIndexes().ToList(); @@ -690,10 +693,10 @@ public virtual void Index_removed_when_covered_by_an_inherited_index() Assert.False(derivedDependentEntityType.GetDeclaredForeignKeys().Single().IsUnique); Assert.Empty(derivedDependentEntityType.GetDeclaredIndexes()); - AssertEqual(initialProperties, derivedDependentEntityType.GetProperties()); - AssertEqual(initialKeys, derivedDependentEntityType.GetKeys()); - AssertEqual(initialIndexes, derivedDependentEntityType.GetIndexes()); - AssertEqual(initialForeignKeys, derivedDependentEntityType.GetForeignKeys()); + Fixture.AssertEqual(initialProperties, derivedDependentEntityType.GetProperties()); + Fixture.AssertEqual(initialKeys, derivedDependentEntityType.GetKeys()); + Fixture.AssertEqual(initialIndexes, derivedDependentEntityType.GetIndexes()); + Fixture.AssertEqual(initialForeignKeys, derivedDependentEntityType.GetForeignKeys()); } [ConditionalFact] diff --git a/test/EFCore.Tests/ModelBuilding/ManyToManyTestBase.cs b/test/EFCore.Tests/ModelBuilding/ManyToManyTestBase.cs index b9f136e5026..4a4a29c2468 100644 --- a/test/EFCore.Tests/ModelBuilding/ManyToManyTestBase.cs +++ b/test/EFCore.Tests/ModelBuilding/ManyToManyTestBase.cs @@ -13,6 +13,11 @@ public abstract partial class ModelBuilderTest { public abstract class ManyToManyTestBase : ModelBuilderTestBase { + public ManyToManyTestBase(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + [ConditionalFact] public virtual void Discovers_navigations() { @@ -1025,7 +1030,7 @@ public virtual void Can_use_implicit_shared_type_with_implicit_relationships_as_ Assert.Equal( CoreStrings.ClashingSharedType(typeof(Dictionary).ShortDisplayName()), - Assert.Throws(() => modelBuilder.Entity>()).Message); + Assert.Throws(modelBuilder.Entity>).Message); modelBuilder.FinalizeModel(); } @@ -1086,9 +1091,9 @@ public virtual void Can_use_implicit_shared_type_with_default_name_and_implicit_ Assert.Equal( CoreStrings.ClashingSharedType(typeof(Dictionary).ShortDisplayName()), - Assert.Throws(() => modelBuilder.Entity>()).Message); + Assert.Throws(modelBuilder.Entity>).Message); - modelBuilder.FinalizeModel(); + AssertEqual(modelBuilder.Model, modelBuilder.FinalizeModel()); } [ConditionalFact] diff --git a/test/EFCore.Tests/ModelBuilding/ManyToOneTestBase.cs b/test/EFCore.Tests/ModelBuilding/ManyToOneTestBase.cs index 535a8587f5a..a0e34fe7d36 100644 --- a/test/EFCore.Tests/ModelBuilding/ManyToOneTestBase.cs +++ b/test/EFCore.Tests/ModelBuilding/ManyToOneTestBase.cs @@ -7,8 +7,13 @@ 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) + { + } + [ConditionalFact] public virtual void Finds_existing_navigations_and_uses_associated_FK() { @@ -886,7 +891,6 @@ public virtual void Can_use_non_PK_principal() Assert.Same(principalKey, principalType.FindPrimaryKey()); Assert.Same(dependentKey, dependentType.FindPrimaryKey()); - expectedPrincipalProperties.Add(fk.PrincipalKey.Properties.Single()); AssertEqual(expectedPrincipalProperties, principalType.GetProperties()); expectedDependentProperties.Add(fk.Properties.Single()); AssertEqual(expectedDependentProperties, dependentType.GetProperties()); @@ -1019,9 +1023,7 @@ public virtual void Can_have_FK_by_convention_specified_with_explicit_principal_ Assert.Contains(fk.PrincipalKey, principalType.GetKeys()); Assert.NotSame(principalKey, fk.PrincipalKey); - expectedPrincipalProperties.Add(fk.PrincipalKey.Properties.Single()); AssertEqual(expectedPrincipalProperties, principalType.GetProperties()); - expectedDependentProperties.Add(fk.Properties.Single()); AssertEqual(expectedDependentProperties, dependentType.GetProperties()); Assert.Equal(dependentType.GetForeignKeys().Count(), dependentType.GetIndexes().Count()); @@ -1068,9 +1070,7 @@ public virtual void Can_have_FK_by_convention_specified_with_explicit_principal_ Assert.Contains(fk.PrincipalKey, principalType.GetKeys()); Assert.NotSame(principalKey, fk.PrincipalKey); - expectedPrincipalProperties.Add(fk.PrincipalKey.Properties.Single()); AssertEqual(expectedPrincipalProperties, principalType.GetProperties()); - expectedDependentProperties.Add(fk.Properties.Single()); AssertEqual(expectedDependentProperties, dependentType.GetProperties()); Assert.Equal(dependentType.GetForeignKeys().Count(), dependentType.GetIndexes().Count()); @@ -1688,7 +1688,7 @@ public virtual void Removes_existing_unidirectional_one_to_one_relationship() // so now the RelationshipDiscoveryConvention should be able // to unambiguously and automatically match up Nob.Hob and Hob.Nobs var oldFk = principalType.GetForeignKeys().Single(); - AssertEqual(new[] { nameof(Nob.HobId1), nameof(Nob.HobId2) }, oldFk.Properties.Select(p => p.Name)); + Assert.Equal(new[] { nameof(Nob.HobId1), nameof(Nob.HobId2) }, oldFk.Properties.Select(p => p.Name)); Assert.Same(oldFk, dependentType.GetNavigations().Single(n => n.Name == nameof(Hob.Nobs)).ForeignKey); Assert.Same(oldFk, principalType.GetNavigations().Single(n => n.Name == nameof(Nob.Hob)).ForeignKey); Assert.False(oldFk.IsUnique); diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericRelationshipStringTest.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericRelationshipStringTest.cs index 53f70f1a0a9..8cf02430aa4 100644 --- a/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericRelationshipStringTest.cs +++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericRelationshipStringTest.cs @@ -9,6 +9,11 @@ public class ModelBuilderGenericRelationshipStringTest : ModelBuilderGenericTest { public class GenericOneToManyString : OneToManyTestBase { + public GenericOneToManyString(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) @@ -17,6 +22,10 @@ protected override TestModelBuilder CreateTestModelBuilder( public class GenericManyToOneString : ManyToOneTestBase { + public GenericManyToOneString(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) @@ -25,6 +34,10 @@ protected override TestModelBuilder CreateTestModelBuilder( public class GenericManyToManyString : ManyToManyTestBase { + public GenericManyToManyString(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) @@ -33,6 +46,10 @@ protected override TestModelBuilder CreateTestModelBuilder( public class GenericOneToOneString : OneToOneTestBase { + public GenericOneToOneString(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) @@ -41,6 +58,11 @@ protected override TestModelBuilder CreateTestModelBuilder( public class GenericOwnedTypesString : OwnedTypesTestBase { + public GenericOwnedTypesString(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericRelationshipTypeTest.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericRelationshipTypeTest.cs index 823b04165ea..ad9e217b3cd 100644 --- a/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericRelationshipTypeTest.cs +++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericRelationshipTypeTest.cs @@ -9,6 +9,11 @@ public class ModelBuilderGenericRelationshipTypeTest : ModelBuilderGenericTest { public class GenericOneToOneType : OneToOneTestBase { + public GenericOneToOneType(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) @@ -17,6 +22,11 @@ protected override TestModelBuilder CreateTestModelBuilder( public class GenericNonRelationshipTest : NonRelationshipTestBase { + public GenericNonRelationshipTest(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs index 8192897ba61..0024ac8eea6 100644 --- a/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs +++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs @@ -47,6 +47,11 @@ public void Can_discover_large_models_through_navigations() public class GenericNonRelationship : NonRelationshipTestBase { + public GenericNonRelationship(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) @@ -68,6 +73,11 @@ public virtual void Changing_propertyInfo_updates_Property() public class GenericComplexType : ComplexTypeTestBase { + public GenericComplexType(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) @@ -92,14 +102,24 @@ public virtual void Changing_propertyInfo_updates_Property() 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 class GenericOwnedTypes: OwnedTypesTestBase { + public GenericOwnedTypes(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) @@ -108,6 +128,11 @@ protected override TestModelBuilder CreateTestModelBuilder( public class GenericOneToMany : OneToManyTestBase { + public GenericOneToMany(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) @@ -116,6 +141,11 @@ protected override TestModelBuilder CreateTestModelBuilder( public class GenericManyToOne : ManyToOneTestBase { + public GenericManyToOne(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) @@ -124,6 +154,11 @@ protected override TestModelBuilder CreateTestModelBuilder( public class GenericManyToMany : ManyToManyTestBase { + public GenericManyToMany(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) @@ -132,6 +167,11 @@ protected override TestModelBuilder CreateTestModelBuilder( public class GenericOneToOne : OneToOneTestBase { + public GenericOneToOne(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericStringTest.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericStringTest.cs index 7370d0dcbba..711b77f3794 100644 --- a/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericStringTest.cs +++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericStringTest.cs @@ -13,6 +13,11 @@ public class ModelBuilderNonGenericStringTest : ModelBuilderNonGenericTest { public class NonGenericStringOwnedTypes : OwnedTypesTestBase { + public NonGenericStringOwnedTypes(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) @@ -24,11 +29,16 @@ public override void OwnedType_can_derive_from_Collection() CoreStrings.AmbiguousSharedTypeEntityTypeName( "Microsoft.EntityFrameworkCore.ModelBuilding.ModelBuilderTest+DependentEntity"), Assert.Throws( - () => base.OwnedType_can_derive_from_Collection()).Message); + base.OwnedType_can_derive_from_Collection).Message); } public class NonGenericStringOneToManyType : OneToManyTestBase { + public NonGenericStringOneToManyType(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) @@ -42,6 +52,11 @@ public override void WithMany_pointing_to_keyless_entity_throws() public class NonGenericStringManyToOneType : ManyToOneTestBase { + public NonGenericStringManyToOneType(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) @@ -50,6 +65,11 @@ protected override TestModelBuilder CreateTestModelBuilder( public class NonGenericStringOneToOneType : OneToOneTestBase { + public NonGenericStringOneToOneType(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs index d59a6c6d47d..4f87fe4dbd3 100644 --- a/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs +++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs @@ -9,6 +9,11 @@ public class ModelBuilderNonGenericTest : ModelBuilderTest { public class NonGenericNonRelationship : NonRelationshipTestBase { + public NonGenericNonRelationship(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) @@ -17,6 +22,11 @@ protected override TestModelBuilder CreateTestModelBuilder( public class NonGenericComplexType : ComplexTypeTestBase { + public NonGenericComplexType(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) @@ -25,6 +35,11 @@ protected override TestModelBuilder CreateTestModelBuilder( public class NonGenericInheritance : InheritanceTestBase { + public NonGenericInheritance(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) @@ -33,6 +48,11 @@ protected override TestModelBuilder CreateTestModelBuilder( 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() { @@ -55,6 +75,11 @@ protected override TestModelBuilder CreateTestModelBuilder( public class NonGenericOneToMany : OneToManyTestBase { + public NonGenericOneToMany(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + [ConditionalFact] public virtual void HasOne_with_just_string_navigation_for_non_CLR_property_throws() { @@ -140,6 +165,11 @@ protected override TestModelBuilder CreateTestModelBuilder( public class NonGenericManyToOne : ManyToOneTestBase { + public NonGenericManyToOne(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) @@ -148,6 +178,10 @@ protected override TestModelBuilder CreateTestModelBuilder( public class NonGenericManyToMany : ManyToManyTestBase { + public NonGenericManyToMany(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) @@ -156,6 +190,11 @@ protected override TestModelBuilder CreateTestModelBuilder( public class NonGenericOneToOne : OneToOneTestBase { + public NonGenericOneToOne(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericUnqualifiedStringTest.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericUnqualifiedStringTest.cs index edd5889b72a..9d4b2af94d0 100644 --- a/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericUnqualifiedStringTest.cs +++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericUnqualifiedStringTest.cs @@ -9,6 +9,11 @@ public class ModelBuilderNonGenericUnqualifiedStringTest : ModelBuilderNonGeneri { public class NonGenericStringOneToOneType : OneToOneTestBase { + public NonGenericStringOneToOneType(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + protected override TestModelBuilder CreateTestModelBuilder( TestHelpers testHelpers, Action? configure) diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs index a2f9f351722..bf428ba620e 100644 --- a/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs +++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs @@ -4,88 +4,44 @@ #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 static void AssertEqual( - IEnumerable expectedNames, - IEnumerable actualNames, - StringComparer? stringComparer = null) + public abstract class ModelBuilderTestBase : IClassFixture { - stringComparer ??= StringComparer.Ordinal; - Assert.Equal( - new SortedSet(expectedNames, stringComparer), - new SortedSet(actualNames, stringComparer), - stringComparer); - } + protected ModelBuilderTestBase(ModelBuilderFixtureBase fixture) + { + Fixture = fixture; + } - public static void AssertEqual( - IEnumerable expectedProperties, - IEnumerable actualProperties, - PropertyComparer? propertyComparer = null) - { - propertyComparer ??= new PropertyComparer(compareAnnotations: false); - Assert.Equal( - new SortedSet(expectedProperties, propertyComparer), - new SortedSet(actualProperties, propertyComparer), - propertyComparer); - } + protected virtual ModelBuilderFixtureBase Fixture { get; } - public static void AssertEqual( - IEnumerable expectedNavigations, - IEnumerable actualNavigations, - NavigationComparer? navigationComparer = null) - { - navigationComparer ??= new NavigationComparer(compareAnnotations: false); - Assert.Equal( - new SortedSet(expectedNavigations, navigationComparer), - new SortedSet(actualNavigations, navigationComparer), - navigationComparer); - } + protected virtual TestModelBuilder CreateModelBuilder(Action? configure = null) + => CreateTestModelBuilder(InMemoryTestHelpers.Instance, configure); - public static void AssertEqual( - IEnumerable expectedKeys, - IEnumerable actualKeys, - TestKeyComparer? testKeyComparer = null) - { - testKeyComparer ??= new TestKeyComparer(compareAnnotations: false); - Assert.Equal( - new SortedSet(expectedKeys, testKeyComparer), - new SortedSet(actualKeys, testKeyComparer), - testKeyComparer); - } + protected abstract TestModelBuilder CreateTestModelBuilder( + TestHelpers testHelpers, + Action? configure = null); - public static void AssertEqual( - IEnumerable expectedForeignKeys, - IEnumerable actualForeignKeys, - ForeignKeyStrictComparer? foreignKeyComparer = null) - { - foreignKeyComparer ??= new ForeignKeyStrictComparer(compareAnnotations: false); - Assert.Equal( - new SortedSet(expectedForeignKeys, foreignKeyComparer), - new SortedSet(actualForeignKeys, foreignKeyComparer), - foreignKeyComparer); - } + public virtual void AssertEqual( + IReadOnlyModel expected, + IReadOnlyModel actual, + bool compareAnnotations = false) + => Fixture.AssertEqual(expected, actual, compareAnnotations); - public static void AssertEqual( - IEnumerable expectedIndexes, - IEnumerable actualIndexes, - TestIndexComparer? testIndexComparer = null) - { - testIndexComparer ??= new TestIndexComparer(compareAnnotations: false); - Assert.Equal( - new SortedSet(expectedIndexes, testIndexComparer), - new SortedSet(actualIndexes, testIndexComparer), - testIndexComparer); - } + public virtual void AssertEqual( + IEnumerable expectedProperties, + IEnumerable actualProperties, + bool assertOrder = false, + bool compareAnnotations = false) + => Fixture.AssertEqual(expectedProperties, actualProperties, assertOrder, compareAnnotations); - public abstract class ModelBuilderTestBase - { - protected virtual TestModelBuilder CreateModelBuilder(Action? configure = null) - => CreateTestModelBuilder(InMemoryTestHelpers.Instance, configure); + public virtual IReadOnlyModel Clone(IReadOnlyModel model) + => Fixture.Clone(model); protected TestModelBuilder HobNobBuilder() { @@ -96,10 +52,1018 @@ protected TestModelBuilder HobNobBuilder() return builder; } + } - protected abstract TestModelBuilder CreateTestModelBuilder( - TestHelpers testHelpers, - Action? configure = null); + public 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 class TestModelBuilder : IInfrastructure diff --git a/test/EFCore.Tests/ModelBuilding/NonRelationshipTestBase.cs b/test/EFCore.Tests/ModelBuilding/NonRelationshipTestBase.cs index 65a22615717..b9ab0dbdaef 100644 --- a/test/EFCore.Tests/ModelBuilding/NonRelationshipTestBase.cs +++ b/test/EFCore.Tests/ModelBuilding/NonRelationshipTestBase.cs @@ -16,6 +16,11 @@ public abstract partial class ModelBuilderTest { public abstract class NonRelationshipTestBase : ModelBuilderTestBase { + public NonRelationshipTestBase(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + [ConditionalFact] public void Can_set_model_annotation() { @@ -657,8 +662,7 @@ public virtual void Key_properties_cannot_be_made_optional() CreateModelBuilder().Entity( b => { - b.HasAlternateKey( - e => new { e.Down }); + b.HasAlternateKey(e => new { e.Down }); b.Property(e => e.Down).IsRequired(false); })).Message); @@ -1913,6 +1917,7 @@ public virtual void Can_add_multiple_indexes() entityBuilder.HasIndex(ix => ix.Id, "Descending").IsDescending(); var model = modelBuilder.FinalizeModel(); + AssertEqual(modelBuilder.Model, model); var entityType = model.FindEntityType(typeof(Customer))!; var idProperty = entityType.FindProperty(nameof(Customer.Id))!; @@ -1965,7 +1970,7 @@ public virtual void Can_set_primary_key_by_convention_for_user_specified_shadow_ entityBuilder.Property("Id"); Assert.NotNull(entityType.FindPrimaryKey()); - AssertEqual(new[] { "Id" }, entityType.FindPrimaryKey()!.Properties.Select(p => p.Name)); + Assert.Equal(new[] { "Id" }, entityType.FindPrimaryKey()!.Properties.Select(p => p.Name)); } [ConditionalFact] @@ -2528,8 +2533,7 @@ public virtual void PrimitiveCollection_Key_properties_cannot_be_made_optional() CreateModelBuilder().Entity( b => { - b.HasAlternateKey( - e => new { e.Down }); + b.HasAlternateKey(e => new { e.Down }); b.PrimitiveCollection(e => e.Down).IsRequired(false); })).Message); @@ -2928,7 +2932,7 @@ public virtual void Can_set_primary_key_by_convention_for_user_specified_shadow_ entityBuilder.PrimitiveCollection>("Id"); Assert.NotNull(entityType.FindPrimaryKey()); - AssertEqual(new[] { "Id" }, entityType.FindPrimaryKey()!.Properties.Select(p => p.Name)); + Assert.Equal(new[] { "Id" }, entityType.FindPrimaryKey()!.Properties.Select(p => p.Name)); } [ConditionalFact] @@ -2987,19 +2991,21 @@ public virtual void Can_set_alternate_key_for_primitive_collection_on_an_entity_ { b.PrimitiveCollection(e => e.CollectionCompanyId); b.HasAlternateKey(e => e.CollectionCompanyId); + b.HasAlternateKey(e => e.CollectionId); + b.HasKey(e => e.Id); }); - var entity = modelBuilder.Model.FindEntityType(typeof(EntityWithFields))!; - var properties = entity.GetProperties(); - Assert.Single(properties); - var property = properties.Single(); - Assert.Equal(nameof(EntityWithFields.CollectionCompanyId), property.Name); + var model = modelBuilder.FinalizeModel(); + AssertEqual(modelBuilder.Model, model); + + var entity = model.FindEntityType(typeof(EntityWithFields))!; + var property = entity.FindProperty(nameof(EntityWithFields.CollectionCompanyId))!; Assert.Null(property.PropertyInfo); Assert.NotNull(property.FieldInfo); Assert.NotNull(property.GetElementType()); var keys = entity.GetKeys(); - var key = Assert.Single(keys); - Assert.Equal(properties, key.Properties); + Assert.Equal(3, keys.Count()); + Assert.Single(keys.Where(k => k.Properties.All(p => p == property))); } [ConditionalFact] diff --git a/test/EFCore.Tests/ModelBuilding/OneToManyTestBase.cs b/test/EFCore.Tests/ModelBuilding/OneToManyTestBase.cs index 0db49908f92..1918632e4cb 100644 --- a/test/EFCore.Tests/ModelBuilding/OneToManyTestBase.cs +++ b/test/EFCore.Tests/ModelBuilding/OneToManyTestBase.cs @@ -9,6 +9,11 @@ public abstract partial class ModelBuilderTest { public abstract class OneToManyTestBase : ModelBuilderTestBase { + public OneToManyTestBase(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + [ConditionalFact] public virtual void Finds_existing_navigations_and_uses_associated_FK() { @@ -899,7 +904,6 @@ public virtual void Can_use_non_PK_principal() Assert.Same(principalKey, principalType.FindPrimaryKey()); Assert.Same(dependentKey, dependentType.FindPrimaryKey()); - expectedPrincipalProperties.Add(fk.PrincipalKey.Properties.Single()); AssertEqual(expectedPrincipalProperties, principalType.GetProperties()); expectedDependentProperties.Add(fk.Properties.Single()); AssertEqual(expectedDependentProperties, dependentType.GetProperties()); @@ -1093,9 +1097,7 @@ public virtual void Can_have_FK_by_convention_specified_with_explicit_principal_ Assert.Contains(fk.PrincipalKey, principalType.GetKeys()); Assert.NotSame(principalKey, fk.PrincipalKey); - expectedPrincipalProperties.Add(fk.PrincipalKey.Properties.Single()); AssertEqual(expectedPrincipalProperties, principalType.GetProperties()); - expectedDependentProperties.Add(fk.Properties.Single()); AssertEqual(expectedDependentProperties, dependentType.GetProperties()); Assert.Equal(dependentType.GetForeignKeys().Count(), dependentType.GetIndexes().Count()); @@ -1142,9 +1144,7 @@ public virtual void Can_have_FK_by_convention_specified_with_explicit_principal_ Assert.Contains(fk.PrincipalKey, principalType.GetKeys()); Assert.NotSame(principalKey, fk.PrincipalKey); - expectedPrincipalProperties.Add(fk.PrincipalKey.Properties.Single()); AssertEqual(expectedPrincipalProperties, principalType.GetProperties()); - expectedDependentProperties.Add(fk.Properties.Single()); AssertEqual(expectedDependentProperties, dependentType.GetProperties()); Assert.Equal(dependentType.GetForeignKeys().Count(), dependentType.GetIndexes().Count()); @@ -1191,7 +1191,6 @@ public virtual void Can_have_FK_semi_specified_with_explicit_PK() var principalKey = principalType.FindPrimaryKey(); Assert.Same(principalKey, fk.PrincipalKey); - expectedPrincipalProperties.Add(fk.PrincipalKey.Properties.Single()); AssertEqual(expectedPrincipalProperties, principalType.GetProperties()); var fkProperty = fk.Properties.Single(); Assert.False(fkProperty.IsNullable); @@ -1237,7 +1236,6 @@ public virtual void Can_specify_requiredness_after_OnDelete() var principalKey = principalType.FindPrimaryKey(); Assert.Same(principalKey, fk.PrincipalKey); - expectedPrincipalProperties.Add(fk.PrincipalKey.Properties.Single()); AssertEqual(expectedPrincipalProperties, principalType.GetProperties()); var fkProperty = fk.Properties.Single(); Assert.False(fkProperty.IsNullable); @@ -1394,14 +1392,13 @@ public virtual void Principal_key_by_convention_is_not_replaced_with_new_incompa var model = modelBuilder.Model; modelBuilder .Entity().HasMany(e => e.Pickles).WithOne(e => e.BigMak) - .HasForeignKey( - e => new { e.BurgerId, e.Id }); + .HasForeignKey(e => new { e.BurgerId, e.Id }); modelBuilder.Ignore(); var dependentType = model.FindEntityType(typeof(Pickle)); var principalType = model.FindEntityType(typeof(BigMak)); - var modelClone = modelBuilder.Model.Clone(); + var modelClone = Clone(modelBuilder.Model); var nonPrimaryPrincipalKey = modelClone.FindEntityType(typeof(BigMak).FullName) .GetKeys().First(k => !k.IsPrimaryKey()); var dependentKey = dependentType.FindPrimaryKey(); @@ -1419,8 +1416,8 @@ public virtual void Principal_key_by_convention_is_not_replaced_with_new_incompa Assert.Equal("Pickles", principalType.GetNavigations().Single().Name); Assert.Same(fk, dependentType.GetNavigations().Single().ForeignKey); Assert.Same(fk, principalType.GetNavigations().Single().ForeignKey); - AssertEqual(expectedPrincipalProperties.Select(p => p.Name), principalType.GetProperties().Select(p => p.Name)); - AssertEqual(expectedDependentProperties.Select(p => p.Name), dependentType.GetProperties().Select(p => p.Name)); + Assert.Equivalent(expectedPrincipalProperties.Select(p => p.Name), principalType.GetProperties().Select(p => p.Name)); + AssertEqual(expectedDependentProperties, dependentType.GetProperties()); Assert.Empty(principalType.GetForeignKeys()); var primaryPrincipalKey = principalType.FindPrimaryKey(); @@ -1441,8 +1438,7 @@ public virtual void Explicit_principal_key_is_not_replaced_with_new_primary_key( var model = modelBuilder.Model; modelBuilder .Entity().HasMany(e => e.Pickles).WithOne(e => e.BigMak) - .HasPrincipalKey( - e => new { e.Id }); + .HasPrincipalKey(e => new { e.Id }); modelBuilder.Ignore(); var principalType = model.FindEntityType(typeof(BigMak)); @@ -1480,12 +1476,10 @@ public virtual void Creates_both_navigations_and_uses_existing_composite_FK() { var modelBuilder = CreateModelBuilder(); var model = modelBuilder.Model; - modelBuilder.Entity().HasKey( - c => new { c.Id1, c.Id2 }); + modelBuilder.Entity().HasKey(c => new { c.Id1, c.Id2 }); modelBuilder .Entity().HasOne(e => e.Whoopper).WithMany() - .HasForeignKey( - c => new { c.BurgerId1, c.BurgerId2 }); + .HasForeignKey(c => new { c.BurgerId1, c.BurgerId2 }); modelBuilder.Ignore(); modelBuilder.Ignore(); @@ -1497,8 +1491,7 @@ public virtual void Creates_both_navigations_and_uses_existing_composite_FK() modelBuilder .Entity().HasMany(e => e.Tomatoes).WithOne(e => e.Whoopper) - .HasForeignKey( - e => new { e.BurgerId1, e.BurgerId2 }); + .HasForeignKey(e => new { e.BurgerId1, e.BurgerId2 }); modelBuilder.FinalizeModel(); @@ -1522,8 +1515,7 @@ public virtual void Creates_both_navigations_and_creates_composite_FK_specified( var modelBuilder = CreateModelBuilder(); var model = modelBuilder.Model; modelBuilder.Entity( - b => b.HasKey( - c => new { c.Id1, c.Id2 })); + b => b.HasKey(c => new { c.Id1, c.Id2 })); modelBuilder.Entity(); modelBuilder.Ignore(); modelBuilder.Ignore(); @@ -1539,8 +1531,7 @@ public virtual void Creates_both_navigations_and_creates_composite_FK_specified( modelBuilder .Entity().HasMany(e => e.Tomatoes).WithOne(e => e.Whoopper) - .HasForeignKey( - e => new { e.BurgerId1, e.BurgerId2 }); + .HasForeignKey(e => new { e.BurgerId1, e.BurgerId2 }); modelBuilder.FinalizeModel(); @@ -1567,8 +1558,7 @@ public virtual void Can_use_alternate_composite_key() var modelBuilder = CreateModelBuilder(); var model = modelBuilder.Model; modelBuilder.Entity( - b => b.HasKey( - c => new { c.Id1, c.Id2 })); + b => b.HasKey(c => new { c.Id1, c.Id2 })); modelBuilder.Entity(); modelBuilder.Ignore(); modelBuilder.Ignore(); @@ -1586,10 +1576,8 @@ public virtual void Can_use_alternate_composite_key() modelBuilder .Entity().HasMany(e => e.Tomatoes).WithOne(e => e.Whoopper) - .HasForeignKey( - e => new { e.BurgerId1, e.BurgerId2 }) - .HasPrincipalKey( - e => new { e.AlternateKey1, e.AlternateKey2 }); + .HasForeignKey(e => new { e.BurgerId1, e.BurgerId2 }) + .HasPrincipalKey(e => new { e.AlternateKey1, e.AlternateKey2 }); modelBuilder.FinalizeModel(); @@ -1623,8 +1611,7 @@ public virtual void Can_use_alternate_composite_key_in_any_order() var modelBuilder = CreateModelBuilder(); var model = modelBuilder.Model; modelBuilder.Entity( - b => b.HasKey( - c => new { c.Id1, c.Id2 })); + b => b.HasKey(c => new { c.Id1, c.Id2 })); modelBuilder.Entity(); modelBuilder.Ignore(); modelBuilder.Ignore(); @@ -1642,10 +1629,8 @@ public virtual void Can_use_alternate_composite_key_in_any_order() modelBuilder .Entity().HasMany(e => e.Tomatoes).WithOne(e => e.Whoopper) - .HasPrincipalKey( - e => new { e.AlternateKey1, e.AlternateKey2 }) - .HasForeignKey( - e => new { e.BurgerId1, e.BurgerId2 }); + .HasPrincipalKey(e => new { e.AlternateKey1, e.AlternateKey2 }) + .HasForeignKey(e => new { e.BurgerId1, e.BurgerId2 }); modelBuilder.FinalizeModel(); @@ -1678,8 +1663,7 @@ public virtual void Creates_specified_composite_FK_with_navigation_to_dependent( { var modelBuilder = CreateModelBuilder(); var model = modelBuilder.Model; - modelBuilder.Entity().HasKey( - c => new { c.Id1, c.Id2 }); + modelBuilder.Entity().HasKey(c => new { c.Id1, c.Id2 }); modelBuilder.Entity( b => { @@ -1700,8 +1684,7 @@ public virtual void Creates_specified_composite_FK_with_navigation_to_dependent( modelBuilder .Entity().HasMany(e => e.Tomatoes).WithOne() - .HasForeignKey( - e => new { e.BurgerId1, e.BurgerId2 }); + .HasForeignKey(e => new { e.BurgerId1, e.BurgerId2 }); modelBuilder.FinalizeModel(); @@ -1724,8 +1707,7 @@ public virtual void Creates_specified_composite_FK_with_navigation_to_principal( { var modelBuilder = CreateModelBuilder(); var model = modelBuilder.Model; - modelBuilder.Entity().HasKey( - c => new { c.Id1, c.Id2 }); + modelBuilder.Entity().HasKey(c => new { c.Id1, c.Id2 }); modelBuilder.Entity(); modelBuilder.Ignore(); modelBuilder.Ignore(); @@ -1738,8 +1720,7 @@ public virtual void Creates_specified_composite_FK_with_navigation_to_principal( modelBuilder .Entity().HasMany().WithOne(e => e.Whoopper) - .HasForeignKey( - e => new { e.BurgerId1, e.BurgerId2 }); + .HasForeignKey(e => new { e.BurgerId1, e.BurgerId2 }); modelBuilder.FinalizeModel(); @@ -1763,8 +1744,7 @@ public virtual void Creates_relationship_with_no_navigations_and_specified_compo { var modelBuilder = CreateModelBuilder(); var model = modelBuilder.Model; - modelBuilder.Entity().HasKey( - c => new { c.Id1, c.Id2 }); + modelBuilder.Entity().HasKey(c => new { c.Id1, c.Id2 }); modelBuilder.Entity().HasMany(w => w.Tomatoes).WithOne(t => t.Whoopper); modelBuilder.Entity(); modelBuilder.Ignore(); @@ -1782,8 +1762,7 @@ public virtual void Creates_relationship_with_no_navigations_and_specified_compo modelBuilder .Entity().HasMany().WithOne() - .HasForeignKey( - e => new { e.BurgerId1, e.BurgerId2 }); + .HasForeignKey(e => new { e.BurgerId1, e.BurgerId2 }); modelBuilder.FinalizeModel(); @@ -1807,11 +1786,9 @@ public virtual void Creates_relationship_on_existing_FK_is_using_different_princ { var modelBuilder = CreateModelBuilder(); var model = modelBuilder.Model; - modelBuilder.Entity().HasKey( - c => new { c.Id1, c.Id2 }); + modelBuilder.Entity().HasKey(c => new { c.Id1, c.Id2 }); modelBuilder.Entity().HasOne(e => e.ToastedBun).WithOne(e => e.Whoopper) - .HasForeignKey( - e => new { e.BurgerId1, e.BurgerId2 }); + .HasForeignKey(e => new { e.BurgerId1, e.BurgerId2 }); modelBuilder.Ignore(); modelBuilder.Ignore(); @@ -1823,10 +1800,8 @@ public virtual void Creates_relationship_on_existing_FK_is_using_different_princ modelBuilder .Entity().HasMany().WithOne() - .HasForeignKey( - e => new { e.BurgerId1, e.BurgerId2 }) - .HasPrincipalKey( - e => new { e.AlternateKey1, e.AlternateKey2 }); + .HasForeignKey(e => new { e.BurgerId1, e.BurgerId2 }) + .HasPrincipalKey(e => new { e.AlternateKey1, e.AlternateKey2 }); var navigation = dependentType.GetNavigations().Single(); var existingFk = navigation.ForeignKey; @@ -1857,11 +1832,9 @@ public virtual void Creates_relationship_on_existing_FK_is_using_different_princ { var modelBuilder = CreateModelBuilder(); var model = modelBuilder.Model; - modelBuilder.Entity().HasKey( - c => new { c.Id1, c.Id2 }); + modelBuilder.Entity().HasKey(c => new { c.Id1, c.Id2 }); modelBuilder.Entity().HasOne(e => e.ToastedBun).WithOne(e => e.Whoopper) - .HasForeignKey( - e => new { e.BurgerId1, e.BurgerId2 }); + .HasForeignKey(e => new { e.BurgerId1, e.BurgerId2 }); modelBuilder.Ignore(); modelBuilder.Ignore(); @@ -1873,10 +1846,8 @@ public virtual void Creates_relationship_on_existing_FK_is_using_different_princ modelBuilder .Entity().HasMany().WithOne() - .HasPrincipalKey( - e => new { e.AlternateKey1, e.AlternateKey2 }) - .HasForeignKey( - e => new { e.BurgerId1, e.BurgerId2 }); + .HasPrincipalKey(e => new { e.AlternateKey1, e.AlternateKey2 }) + .HasForeignKey(e => new { e.BurgerId1, e.BurgerId2 }); var existingFk = dependentType.GetNavigations().Single().ForeignKey; Assert.Same(existingFk, principalType.GetNavigations().Single().ForeignKey); diff --git a/test/EFCore.Tests/ModelBuilding/OneToOneTestBase.cs b/test/EFCore.Tests/ModelBuilding/OneToOneTestBase.cs index 3a096fed7c5..641a97bbdf7 100644 --- a/test/EFCore.Tests/ModelBuilding/OneToOneTestBase.cs +++ b/test/EFCore.Tests/ModelBuilding/OneToOneTestBase.cs @@ -11,6 +11,11 @@ public abstract partial class ModelBuilderTest { public abstract class OneToOneTestBase : ModelBuilderTestBase { + public OneToOneTestBase(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + [ConditionalFact] public virtual void Finds_existing_navigations_and_uses_associated_FK() { @@ -206,7 +211,6 @@ public virtual void Creates_both_navigations_and_shadow_FK_if_existing_FK() Assert.Same(fk.DependentToPrincipal, dependentType.GetNavigations().Single()); Assert.Same(fk.PrincipalToDependent, principalType.GetNavigations().Single()); AssertEqual(expectedPrincipalProperties, principalType.GetProperties()); - expectedDependentProperties.Add(fk.Properties.Single()); AssertEqual(expectedDependentProperties, dependentType.GetProperties()); Assert.Empty(principalType.GetForeignKeys()); Assert.Same(principalKey, principalType.FindPrimaryKey()); @@ -1478,7 +1482,6 @@ public virtual void Creates_principal_key_when_specified_on_principal() Assert.Same(fk, dependentType.GetNavigations().Single().ForeignKey); Assert.Same(fk, principalType.GetNavigations().Single().ForeignKey); Assert.Equal(expectedPrincipalProperties, principalType.GetProperties()); - expectedDependentProperties.Add(fk.Properties.Single()); AssertEqual(expectedDependentProperties, dependentType.GetProperties()); Assert.Empty(principalType.GetForeignKeys()); Assert.Same(fk.PrincipalKey, principalType.GetKeys().First(k => k != principalKey)); @@ -3451,7 +3454,6 @@ public virtual void Unspecified_FK_can_be_made_optional() Assert.False(fk.IsRequired); AssertEqual(expectedPrincipalProperties, principalType.GetProperties()); - expectedDependentProperties.AddRange(fk.Properties); AssertEqual(expectedDependentProperties, dependentType.GetProperties()); } @@ -3473,7 +3475,6 @@ public virtual void Unspecified_FK_can_be_made_optional_in_any_order() Assert.False(fk.IsRequired); AssertEqual(expectedPrincipalProperties, principalType.GetProperties()); - expectedDependentProperties.AddRange(fk.Properties); AssertEqual(expectedDependentProperties, dependentType.GetProperties()); } @@ -3497,7 +3498,6 @@ public virtual void Unspecified_FK_can_be_made_required() Assert.True(fk.Properties.All(p => !p.IsNullable)); AssertEqual(expectedPrincipalProperties, principalType.GetProperties()); - expectedDependentProperties.AddRange(fk.Properties); AssertEqual(expectedDependentProperties, dependentType.GetProperties()); } diff --git a/test/EFCore.Tests/ModelBuilding/OwnedTypesTestBase.cs b/test/EFCore.Tests/ModelBuilding/OwnedTypesTestBase.cs index df7e853c2bc..da2da4d44d3 100644 --- a/test/EFCore.Tests/ModelBuilding/OwnedTypesTestBase.cs +++ b/test/EFCore.Tests/ModelBuilding/OwnedTypesTestBase.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. // ReSharper disable InconsistentNaming @@ -8,6 +8,11 @@ public abstract partial class ModelBuilderTest { public abstract class OwnedTypesTestBase : ModelBuilderTestBase { + public OwnedTypesTestBase(ModelBuilderFixtureBase fixture) + : base(fixture) + { + } + [ConditionalFact] public virtual void Can_configure_owned_type() { @@ -1183,6 +1188,7 @@ public virtual void Can_configure_chained_ownerships() modelBuilder.Entity(); var model = modelBuilder.FinalizeModel(); + AssertEqual(modelBuilder.Model, model); VerifyOwnedBookLabelModel(model); } @@ -1241,6 +1247,7 @@ public virtual void Can_configure_chained_ownerships_different_order() modelBuilder.Entity(); var model = modelBuilder.FinalizeModel(); + AssertEqual(modelBuilder.Model, model); VerifyOwnedBookLabelModel(model); } diff --git a/test/EFCore.Tests/ModelBuilding/ShadowEntityTypeTest.cs b/test/EFCore.Tests/ModelBuilding/ShadowEntityTypeTest.cs index 351f862b583..2c7de7bc337 100644 --- a/test/EFCore.Tests/ModelBuilding/ShadowEntityTypeTest.cs +++ b/test/EFCore.Tests/ModelBuilding/ShadowEntityTypeTest.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. #nullable enable