550 lines
19 KiB
C#
550 lines
19 KiB
C#
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
|
|
|
namespace ProductivityApiUnitTests
|
|
{
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Data.Entity;
|
|
using System.Data.Entity.Core.Objects.DataClasses;
|
|
using System.Data.Entity.Infrastructure;
|
|
using System.Data.Entity.Internal;
|
|
using System.Data.Entity.ModelConfiguration.Configuration.Types;
|
|
using System.Data.Entity.Resources;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using Moq;
|
|
using Xunit;
|
|
|
|
public class FakeEntity1
|
|
{
|
|
}
|
|
|
|
public class FakeEntity2
|
|
{
|
|
}
|
|
|
|
public class FakeEntity3
|
|
{
|
|
}
|
|
|
|
public class FakeEntity4
|
|
{
|
|
}
|
|
|
|
public class FakeEntity5
|
|
{
|
|
}
|
|
|
|
public class FakeEntity6
|
|
{
|
|
}
|
|
|
|
public class FakeEntity7
|
|
{
|
|
}
|
|
|
|
public class FakeEntity8
|
|
{
|
|
}
|
|
|
|
public class FakeEntity9
|
|
{
|
|
}
|
|
|
|
public class FakeEntity10
|
|
{
|
|
}
|
|
|
|
public class FakeEntity11
|
|
{
|
|
}
|
|
|
|
public class FakeEntity12
|
|
{
|
|
}
|
|
|
|
public class FakeEntity13
|
|
{
|
|
}
|
|
|
|
public class FakeEntity14
|
|
{
|
|
}
|
|
|
|
public class FakeEntity15
|
|
{
|
|
}
|
|
|
|
public class FakeEntity16
|
|
{
|
|
}
|
|
|
|
public class FakeEntity17
|
|
{
|
|
}
|
|
|
|
public class FakeEntity18
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Unit tests for the DbSet/ObjectSet discovery service.
|
|
/// </summary>
|
|
public class SetDiscoveryTests : TestBase
|
|
{
|
|
#region Positive DbContext discovery and initialization tests
|
|
|
|
private class FakeDbContextWithDbSets : DbContext
|
|
{
|
|
public FakeDbContextWithDbSets()
|
|
: base("this=is=not=valid")
|
|
{
|
|
}
|
|
|
|
// Should be detected: DbSets with no modifiers
|
|
public DbSet<FakeEntity1> PublicGetSet { get; set; }
|
|
protected IDbSet<FakeEntity2> ProtectedGetSet { get; set; }
|
|
internal DbSet<FakeEntity3> InternalGetSet { get; set; }
|
|
protected internal IDbSet<FakeEntity4> InternalProtectedGetSet { get; set; }
|
|
private DbSet<FakeEntity5> PrivateGetSet { get; set; }
|
|
|
|
// Should be detected: Public DbSets setter modifiers
|
|
public IDbSet<FakeEntity6> PrivateSet { get; private set; }
|
|
public DbSet<FakeEntity7> ProtectedSet { get; protected set; }
|
|
public IDbSet<FakeEntity8> InternalSet { get; internal set; }
|
|
public DbSet<FakeEntity9> InternalProtectedSet { get; protected internal set; }
|
|
|
|
// Should be detected: Public DbSets getter modifiers
|
|
public DbSet<FakeEntity10> PrivateGet { private get; set; }
|
|
public IDbSet<FakeEntity11> ProtectedGet { protected get; set; }
|
|
public DbSet<FakeEntity12> InternalGet { internal get; set; }
|
|
public IDbSet<FakeEntity13> InternalProtectedGet { protected internal get; set; }
|
|
|
|
// Should be detected: DbSets with no setters
|
|
public DbSet<FakeEntity14> PublicGetNoSet
|
|
{
|
|
get { return null; }
|
|
}
|
|
|
|
protected IDbSet<FakeEntity15> ProtectedGetNoSet
|
|
{
|
|
get { return null; }
|
|
}
|
|
|
|
internal IDbSet<FakeEntity16> InternalGetNoSet
|
|
{
|
|
get { return null; }
|
|
}
|
|
|
|
protected internal DbSet<FakeEntity17> InternalProtectedGetNoSet
|
|
{
|
|
get { return null; }
|
|
}
|
|
|
|
private IDbSet<FakeEntity18> PrivateGetNoSet
|
|
{
|
|
get { return null; }
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void DbSet_and_IDbSet_properties_on_derived_DbContext_are_discovered()
|
|
{
|
|
var expected = new[]
|
|
{
|
|
"PublicGetSet", "ProtectedGetSet", "InternalGetSet", "InternalProtectedGetSet", "PrivateGetSet",
|
|
"PrivateSet", "ProtectedSet", "InternalSet", "InternalProtectedSet",
|
|
"PrivateGet", "ProtectedGet", "InternalGet", "InternalProtectedGet",
|
|
"PublicGetNoSet", "ProtectedGetNoSet", "InternalGetNoSet", "InternalProtectedGetNoSet", "PrivateGetNoSet"
|
|
,
|
|
};
|
|
|
|
AssertExpectedSetsDiscovered(new FakeDbContextWithDbSets(), expected);
|
|
}
|
|
|
|
private class FakeDbContextWithNonSets : DbContext
|
|
{
|
|
public FakeDbContextWithNonSets()
|
|
: base("this=is=not=valid")
|
|
{
|
|
}
|
|
|
|
public DbSet<FakeEntity> Control { get; set; }
|
|
|
|
public IQueryable<FakeEntity> QueryableT { get; set; }
|
|
public IQueryable Queryable { get; set; }
|
|
public IEnumerable<FakeEntity> EnumerableT { get; set; }
|
|
public IEnumerable Enumerable { get; set; }
|
|
public DbQuery<FakeEntity> DbQuery { get; set; }
|
|
}
|
|
|
|
[Fact]
|
|
public void IQueryable_and_DbQuery_properties_on_derived_DbContext_are_ignored()
|
|
{
|
|
AssertExpectedSetsDiscovered(new FakeDbContextWithNonSets(), new[] { "Control" });
|
|
}
|
|
|
|
[Fact]
|
|
public void DbSet_and_IDbSet_properties_with_public_setters_are_initialized()
|
|
{
|
|
using (var context = new FakeDbContextWithDbSets())
|
|
{
|
|
var contextType = typeof(FakeDbContextWithDbSets);
|
|
const BindingFlags binding = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
|
|
|
|
Assert.NotNull(contextType.GetProperty("PublicGetSet", binding).GetValue(context, null));
|
|
Assert.Null(contextType.GetProperty("ProtectedGetSet", binding).GetValue(context, null));
|
|
Assert.Null(contextType.GetProperty("InternalGetSet", binding).GetValue(context, null));
|
|
Assert.Null(contextType.GetProperty("InternalProtectedGetSet", binding).GetValue(context, null));
|
|
Assert.Null(contextType.GetProperty("PrivateGetSet", binding).GetValue(context, null));
|
|
Assert.Null(contextType.GetProperty("PrivateSet", binding).GetValue(context, null));
|
|
Assert.Null(contextType.GetProperty("ProtectedSet", binding).GetValue(context, null));
|
|
Assert.Null(contextType.GetProperty("InternalSet", binding).GetValue(context, null));
|
|
Assert.Null(contextType.GetProperty("InternalProtectedSet", binding).GetValue(context, null));
|
|
Assert.NotNull(contextType.GetProperty("PrivateGet", binding).GetValue(context, null));
|
|
Assert.NotNull(contextType.GetProperty("ProtectedGet", binding).GetValue(context, null));
|
|
Assert.NotNull(contextType.GetProperty("InternalGet", binding).GetValue(context, null));
|
|
Assert.NotNull(contextType.GetProperty("InternalProtectedGet", binding).GetValue(context, null));
|
|
Assert.Null(contextType.GetProperty("PublicGetNoSet", binding).GetValue(context, null));
|
|
Assert.Null(contextType.GetProperty("ProtectedGetNoSet", binding).GetValue(context, null));
|
|
Assert.Null(contextType.GetProperty("InternalGetNoSet", binding).GetValue(context, null));
|
|
Assert.Null(contextType.GetProperty("InternalProtectedGetNoSet", binding).GetValue(context, null));
|
|
Assert.Null(contextType.GetProperty("PrivateGetNoSet", binding).GetValue(context, null));
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void IQueryable_and_DbQuery_properties_with_public_setters_are_not_initialized()
|
|
{
|
|
using (var context = new FakeDbContextWithNonSets())
|
|
{
|
|
Assert.NotNull(context.Control);
|
|
Assert.Null(context.DbQuery);
|
|
Assert.Null(context.Enumerable);
|
|
Assert.Null(context.EnumerableT);
|
|
Assert.Null(context.Queryable);
|
|
Assert.Null(context.QueryableT);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Negative entity types
|
|
|
|
private class FakeDbContextWithInterfaceDbSet : DbContext
|
|
{
|
|
public DbSet<IList> SetProp { get; set; }
|
|
}
|
|
|
|
[Fact]
|
|
public void Discovery_of_DbSet_of_interface_type_throws()
|
|
{
|
|
Assert.Equal(
|
|
Strings.InvalidEntityType(typeof(IList)),
|
|
Assert.Throws<InvalidOperationException>(
|
|
() => new DbSetDiscoveryService(new FakeDbContextWithInterfaceDbSet()).InitializeSets()).Message);
|
|
}
|
|
|
|
private class FakeDbContextWithGenericDbSet : DbContext
|
|
{
|
|
public DbSet<List<FakeEntity>> SetProp { get; set; }
|
|
}
|
|
|
|
[Fact]
|
|
public void Discovery_of_DbSet_of_generic_type_throws()
|
|
{
|
|
Assert.Equal(
|
|
Strings.InvalidEntityType(typeof(List<FakeEntity>)),
|
|
Assert.Throws<InvalidOperationException>(
|
|
() => new DbSetDiscoveryService(new FakeDbContextWithGenericDbSet()).InitializeSets()).Message);
|
|
}
|
|
|
|
private class FakeDbContextWithNestedDbSet : DbContext
|
|
{
|
|
public DbSet<FakeDbContextWithDbSets> SetProp { get; set; }
|
|
}
|
|
|
|
[Fact]
|
|
public void Discovery_of_DbSet_of_nested_type_throws()
|
|
{
|
|
Assert.Equal(
|
|
Strings.InvalidEntityType(typeof(FakeDbContextWithDbSets)),
|
|
Assert.Throws<InvalidOperationException>(
|
|
() => new DbSetDiscoveryService(new FakeDbContextWithNestedDbSet()).InitializeSets()).Message);
|
|
}
|
|
|
|
private class FakeDbContextWithObjectDbSet : DbContext
|
|
{
|
|
public DbSet<object> SetProp { get; set; }
|
|
}
|
|
|
|
[Fact]
|
|
public void Discovery_of_DbSet_of_object_throws()
|
|
{
|
|
Assert.Equal(
|
|
Strings.InvalidEntityType(typeof(Object)),
|
|
Assert.Throws<InvalidOperationException>(
|
|
() => new DbSetDiscoveryService(new FakeDbContextWithObjectDbSet()).InitializeSets()).Message);
|
|
}
|
|
|
|
private class FakeDbContextWithEntityObjectDbSet : DbContext
|
|
{
|
|
public DbSet<EntityObject> SetProp { get; set; }
|
|
}
|
|
|
|
[Fact]
|
|
public void Discovery_of_DbSet_of_EntityObject_throws()
|
|
{
|
|
Assert.Equal(
|
|
Strings.InvalidEntityType(typeof(EntityObject)),
|
|
Assert.Throws<InvalidOperationException>(
|
|
() => new DbSetDiscoveryService(new FakeDbContextWithEntityObjectDbSet()).InitializeSets()).Message);
|
|
}
|
|
|
|
private class FakeDbContextWithStructuralObjectDbSet : DbContext
|
|
{
|
|
public DbSet<StructuralObject> SetProp { get; set; }
|
|
}
|
|
|
|
[Fact]
|
|
public void Discovery_of_DbSet_of_StructuralObject_throws()
|
|
{
|
|
Assert.Equal(
|
|
Strings.InvalidEntityType(typeof(StructuralObject)),
|
|
Assert.Throws<InvalidOperationException>(
|
|
() => new DbSetDiscoveryService(new FakeDbContextWithStructuralObjectDbSet()).InitializeSets()).Message);
|
|
}
|
|
|
|
private class FakeDbContextWithComplexObjectDbSet : DbContext
|
|
{
|
|
public DbSet<ComplexObject> SetProp { get; set; }
|
|
}
|
|
|
|
[Fact]
|
|
public void Discovery_of_DbSet_of_ComplexObject_throws()
|
|
{
|
|
Assert.Equal(
|
|
Strings.InvalidEntityType(typeof(ComplexObject)),
|
|
Assert.Throws<InvalidOperationException>(
|
|
() => new DbSetDiscoveryService(new FakeDbContextWithComplexObjectDbSet()).InitializeSets()).Message);
|
|
}
|
|
|
|
private class FakeDbContextWithStringDbSet : DbContext
|
|
{
|
|
public DbSet<String> SetProp { get; set; }
|
|
}
|
|
|
|
[Fact]
|
|
public void Discovery_of_DbSet_of_string_throws()
|
|
{
|
|
Assert.Equal(
|
|
Strings.InvalidEntityType(typeof(String)),
|
|
Assert.Throws<InvalidOperationException>(
|
|
() => new DbSetDiscoveryService(new FakeDbContextWithStringDbSet()).InitializeSets()).Message);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Positive tests for discovery attributes at the class level
|
|
|
|
[SuppressDbSetInitialization]
|
|
private class DerivedDbContextWithClassLevelSetDiscoverOnly : DbContext
|
|
{
|
|
public DbSet<DBNull> FakeSet1 { get; set; }
|
|
public DbSet<Random> FakeSet2 { get; set; }
|
|
}
|
|
|
|
[Fact]
|
|
public void SuppressDbSetInitializationAttribute_on_context_class_results_in_all_sets_being_found()
|
|
{
|
|
var context = new DerivedDbContextWithClassLevelSetDiscoverOnly();
|
|
DiscoverAndInitializeSets(context, 2);
|
|
|
|
Assert.Null(context.FakeSet1);
|
|
Assert.Null(context.FakeSet2);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Positive tests for discovery attributes at the property level
|
|
|
|
private class DerivedDbContextWithPropertyLevelSetDiscoverOnly : DbContext
|
|
{
|
|
public DbSet<DBNull> FakeSet1 { get; set; }
|
|
|
|
[SuppressDbSetInitialization]
|
|
public DbSet<Random> FakeSet2 { get; set; }
|
|
}
|
|
|
|
[Fact]
|
|
public void SuppressDbSetInitializationAttribute_on_property_results_in_property_still_being_discovered()
|
|
{
|
|
var context = new DerivedDbContextWithPropertyLevelSetDiscoverOnly();
|
|
DiscoverAndInitializeSets(context, 2);
|
|
|
|
Assert.NotNull(context.FakeSet1);
|
|
Assert.Null(context.FakeSet2);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Positive tests for discovery attributes on contexts with inheritance
|
|
|
|
[SuppressDbSetInitialization]
|
|
private class DerivedDbContextWithInheritanceLevel1 : DbContext
|
|
{
|
|
public DbSet<DBNull> FakeSet1 { get; set; }
|
|
}
|
|
|
|
private class DerivedDbContextWithInheritanceLevel2 : DerivedDbContextWithInheritanceLevel1
|
|
{
|
|
public DbSet<Random> FakeSet2 { get; set; }
|
|
}
|
|
|
|
[SuppressDbSetInitialization]
|
|
private class DerivedDbContextWithInheritanceLevel3 : DerivedDbContextWithInheritanceLevel2
|
|
{
|
|
public DbSet<GopherStyleUriParser> FakeSet3 { get; set; }
|
|
}
|
|
|
|
[Fact]
|
|
public void DbSetDiscoveryAttribute_on_class_applies_only_to_properties_in_that_class()
|
|
{
|
|
var context = new DerivedDbContextWithInheritanceLevel3();
|
|
DiscoverAndInitializeSets(context, 3);
|
|
|
|
Assert.Null(context.FakeSet1);
|
|
Assert.NotNull(context.FakeSet2);
|
|
Assert.Null(context.FakeSet3);
|
|
}
|
|
|
|
private class DerivedDbContextForPropertyOverrideLevel1 : DbContext
|
|
{
|
|
public virtual DbSet<Random> FakeSet1 { get; set; }
|
|
}
|
|
|
|
private class DerivedDbContextForPropertyOverrideLevel2 : DerivedDbContextForPropertyOverrideLevel1
|
|
{
|
|
[SuppressDbSetInitialization]
|
|
public override DbSet<Random> FakeSet1 { get; set; }
|
|
}
|
|
|
|
[Fact]
|
|
public void DbSetDiscoveryAttribute_on_overriden_property_is_used()
|
|
{
|
|
var context = new DerivedDbContextForPropertyOverrideLevel2();
|
|
DiscoverAndInitializeSets(context, 1);
|
|
|
|
Assert.Null(context.FakeSet1);
|
|
}
|
|
|
|
private class DerivedDbContextForPropertyHideLevel1 : DbContext
|
|
{
|
|
public DbSet<Random> FakeSet1 { get; set; }
|
|
}
|
|
|
|
private class DerivedDbContextForPropertyHideLevel2 : DerivedDbContextForPropertyHideLevel1
|
|
{
|
|
[SuppressDbSetInitialization]
|
|
public new DbSet<Random> FakeSet1 { get; set; }
|
|
}
|
|
|
|
[Fact]
|
|
public void DbSetDiscoveryAttribute_on_hiding_property_is_used()
|
|
{
|
|
var context = new DerivedDbContextForPropertyHideLevel2();
|
|
DiscoverAndInitializeSets(context, 1);
|
|
|
|
Assert.Null(context.FakeSet1);
|
|
}
|
|
|
|
private class DerivedDbContextWithInheritanceBLevel1 : DbContext
|
|
{
|
|
public virtual DbSet<Random> FakeSet1 { get; set; }
|
|
}
|
|
|
|
[SuppressDbSetInitialization]
|
|
private class DerivedDbContextWithInheritanceBLevel2 : DerivedDbContextWithInheritanceBLevel1
|
|
{
|
|
public override DbSet<Random> FakeSet1 { get; set; }
|
|
}
|
|
|
|
[Fact]
|
|
public void DbSetDiscoveryAttribute_on_class_applies_to_properties_overriden_in_that_class()
|
|
{
|
|
var context = new DerivedDbContextWithInheritanceBLevel2();
|
|
DiscoverAndInitializeSets(context, 1);
|
|
|
|
Assert.Null(context.FakeSet1);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Static tests for SuppressDbSetInitializationAttribute usage
|
|
|
|
[Fact]
|
|
public void DbSetDiscoveryAttribute_does_not_allow_multiple_uses()
|
|
{
|
|
Assert.False(GetDbSetDiscoveryAttributeUsage().AllowMultiple);
|
|
}
|
|
|
|
[Fact]
|
|
public void DbSetDiscoveryAttribute_can_be_applied_to_classes_or_properties_only()
|
|
{
|
|
Assert.Equal(AttributeTargets.Class | AttributeTargets.Property, GetDbSetDiscoveryAttributeUsage().ValidOn);
|
|
}
|
|
|
|
private static AttributeUsageAttribute GetDbSetDiscoveryAttributeUsage()
|
|
{
|
|
return
|
|
(AttributeUsageAttribute)typeof(SuppressDbSetInitializationAttribute).GetCustomAttributes(
|
|
typeof(AttributeUsageAttribute),
|
|
inherit: false).Single();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Helpers
|
|
|
|
internal class EntityTypeConfigurationForMock : EntityTypeConfiguration
|
|
{
|
|
public EntityTypeConfigurationForMock()
|
|
: base(typeof(FakeEntity))
|
|
{
|
|
}
|
|
}
|
|
|
|
private void AssertExpectedSetsDiscovered(DbContext context, IEnumerable<string> expected)
|
|
{
|
|
var mockBuilder = new Mock<DbModelBuilder>();
|
|
var mockConfig = new Mock<EntityTypeConfigurationForMock>();
|
|
mockBuilder.Setup(b => b.Entity(It.IsAny<Type>())).Returns(mockConfig.Object);
|
|
|
|
var discoveryService = new DbSetDiscoveryService(context);
|
|
discoveryService.RegisterSets(mockBuilder.Object);
|
|
|
|
foreach (var setName in expected)
|
|
{
|
|
var name = setName;
|
|
mockConfig.VerifySet(c => c.EntitySetName = name, Times.Once());
|
|
}
|
|
}
|
|
|
|
private static void DiscoverAndInitializeSets(DbContext context, int setCount)
|
|
{
|
|
var mockBuilder = new Mock<DbModelBuilder>();
|
|
var mockConfig = new Mock<EntityTypeConfigurationForMock>();
|
|
mockBuilder.Setup(b => b.Entity(It.IsAny<Type>())).Returns(mockConfig.Object);
|
|
|
|
var discoveryService = new DbSetDiscoveryService(context);
|
|
discoveryService.RegisterSets(mockBuilder.Object);
|
|
|
|
mockBuilder.Verify(b => b.Entity(It.IsAny<Type>()), Times.Exactly(setCount));
|
|
mockConfig.VerifySet(c => c.EntitySetName = It.IsAny<string>(), Times.Exactly(setCount));
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|