Skip to content

Tests for proxy interface handling #2066

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
202 changes: 202 additions & 0 deletions src/NHibernate.Test/Async/StaticProxyTest/InterfaceHandling/Fixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by AsyncGenerator.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------


using System;
using NHibernate.Cfg.MappingSchema;
using NHibernate.Mapping.ByCode;
using NUnit.Framework;

namespace NHibernate.Test.StaticProxyTest.InterfaceHandling
{
using System.Threading.Tasks;
[TestFixture]
public class FixtureAsync : TestCaseMappingByCode
{
private readonly Guid _id = Guid.NewGuid();

protected override HbmMapping GetMappings()
{
var mapper = new ModelMapper();

#region Subclass hierarchy

mapper.Class<EntityClassProxy>(
rc =>
{
rc.Id(x => x.Id);
rc.Property(x => x.Name);
});

mapper.UnionSubclass<SubEntityInterfaceProxy>(
rc =>
{
rc.Proxy(typeof(ISubEntityProxy));

rc.Property(x => x.AnotherName);
});

mapper.UnionSubclass<AnotherSubEntityInterfaceProxy>(
rc =>
{
rc.Proxy(typeof(IAnotherEntityProxy));

rc.Property(x => x.AnotherName);
});

mapper.Class<EntityWithSuperClassInterfaceLookup>(
rc =>
{
rc.Table("ClassWithInterfaceLookup");
rc.Id(x => x.Id);
rc.Property(x => x.Name);
rc.ManyToOne(x => x.EntityLookup, x => x.Class(typeof(EntityClassProxy)));
});

#endregion Subclass hierarchy

mapper.Class<EntitySimple>(
rc =>
{
rc.Id(x => x.Id);
rc.Property(x => x.Name);
});

mapper.Class<EntityExplicitInterface>(
rc =>
{
rc.Id(x => x.Id);
rc.Property(x => x.Name);
});

mapper.Class<EntityMultiInterfaces>(
rc =>
{
rc.Id(x => x.Id);
rc.Property(x => x.Name);
});

mapper.Class<EntityMixExplicitImplicitInterface>(
rc =>
{
rc.Table("multiInterface");
rc.Id(x => x.Id);
rc.Property(x => x.Name);
});

mapper.Class<EntityMultiIdProxy>(
rc =>
{
rc.Proxy(typeof(IMultiIdProxy));
rc.Id(x => x.Id);
rc.Property(x => x.Name);
});

return mapper.CompileMappingForAllExplicitlyAddedEntities();
}

[Test]
public async Task ProxyForBaseSubclassCanBeCreatedAsync()
{
using (var session = OpenSession())
{
var entity = await (session.LoadAsync<EntityClassProxy>(_id));
}
}

//Id access via implicit interface should not lead to proxy initialization
[Test]
public async Task ProxyClassIdAccessByImplicitInterfaceAsync()
{
using (var session = OpenSession())
{
var entity = (IEntity) await (session.LoadAsync<EntitySimple>(_id));
CanAccessIEntityId(entity);
ThrowOnIEntityNameAccess(entity);
Assert.That(entity.Id, Is.EqualTo(_id));

var multiInterface = await (session.LoadAsync<EntityMultiInterfaces>(_id));
CanAccessIEntityId(multiInterface);
CanAccessIEntity2Id(multiInterface);
Assert.That(multiInterface.Id, Is.EqualTo(_id));
}
}

[Test]
public async Task ProxyClassIdAccessExplicitInterfaceAsync()
{
using (var session = OpenSession())
{
var entity = await (session.LoadAsync<EntityExplicitInterface>(_id));

ThrowOnIEntityIdAccess(entity);
Assert.That(entity.Id, Is.EqualTo(_id));
}
}

[Test]
public async Task ProxyClassIdAccessBothImplicitExplicitInterfacesAsync()
{
using (var session = OpenSession())
{
var entity = await (session.LoadAsync<EntityMixExplicitImplicitInterface>(_id));

//IEntity2 is implicit and should be accessible without proxy initialization
CanAccessIEntity2Id(entity);
ThrowOnIEntityIdAccess(entity);
}
}

[Test]
public async Task ProxyInterfaceIdAccessAsync()
{
using (var session = OpenSession())
{
var entity = await (session.LoadAsync<ISubEntityProxy>(_id));

CanAccessIEntityId(entity);
}
}

[KnownBug("GH-2271")]
[Test]
public async Task ProxyInterfaceIdAccessFromDifferentInterfacesAsync()
{
using (var session = OpenSession())
{
var entity = await (session.LoadAsync<IMultiIdProxy>(_id));

CanAccessIEntityId(entity);
CanAccessIEntity2Id(entity);
}
}

private void ThrowOnIEntityNameAccess(IEntity entity)
{
Assert.That(() => entity.Name, Throws.TypeOf<ObjectNotFoundException>(), "IEntity.Name access should lead to proxy initialization");
}

private void ThrowOnIEntityIdAccess(IEntity entity)
{
Assert.That(() => entity.Id, Throws.TypeOf<ObjectNotFoundException>(), "IEntity.Id access should lead to proxy initialization");
}

private void CanAccessIEntityId(IEntity entity)
{
Assert.That(() => entity.Id, Throws.Nothing, "Failed to access proxy IEntity.Id interface");
Assert.That(entity.Id, Is.EqualTo(_id));
}

private void CanAccessIEntity2Id(IEntity2 entity)
{
Assert.That(() => entity.Id, Throws.Nothing, "Failed to access proxy IEntity2.Id interface");
Assert.That(entity.Id, Is.EqualTo(_id));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;

namespace NHibernate.Test.StaticProxyTest.InterfaceHandling
{
public interface IEntity
{
Guid Id { get; set; }

string Name { get; set; }
}

public interface IEntity2
{
Guid Id { get; set; }
}
}
82 changes: 82 additions & 0 deletions src/NHibernate.Test/StaticProxyTest/InterfaceHandling/Entities.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using System;

namespace NHibernate.Test.StaticProxyTest.InterfaceHandling
{
public class EntitySimple : IEntity
{
public virtual Guid Id { get; set; }

public virtual string Name { get; set; }
}

public class EntityMultiInterfaces : IEntity, IEntity2
{
public virtual Guid Id { get; set; }

public virtual string Name { get; set; }
}

public class EntityExplicitInterface : IEntity
{
private Guid id;
private string name;

public virtual Guid Id { get; set; }

public virtual string Name { get; set; }

Guid IEntity.Id
{
get => id;
set => id = value;
}

string IEntity.Name
{
get => name;
set => name = value;
}
}

//Proxy contains IEntity.Id and IEntity2.Id
public interface IMultiIdProxy : IEntity, IEntity2
{
}

public class EntityMultiIdProxy : IMultiIdProxy
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
}

public class EntityMixExplicitImplicitInterface : IEntity, IEntity2
{
private Guid id;
private string name;

public virtual Guid Id { get; set; }

public virtual string Name { get; set; }

Guid IEntity.Id
{
get => id;
set => id = value;
}

string IEntity.Name
{
get => name;
set => name = value;
}
}

public class EntityWithSuperClassInterfaceLookup
{
public virtual Guid Id { get; set; }

public virtual string Name { get; set; }

public virtual IEntity EntityLookup { get; set; }
}
}
Loading