Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

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
}
}