Skip to content

Commit

Permalink
add tests for readonly collections & nhibernate
Browse files Browse the repository at this point in the history
  • Loading branch information
lofcz committed Jan 8, 2025
1 parent 64de6a6 commit 924a8a0
Show file tree
Hide file tree
Showing 5 changed files with 589 additions and 45 deletions.
165 changes: 164 additions & 1 deletion FastCloner.Tests/DbTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,169 @@
using System.Data.Common;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using FluentNHibernate.Mapping;
using NHibernate.Cfg;
using NHibernate.Cfg.MappingSchema;
using NHibernate.Collection;
using NHibernate.Mapping.ByCode;
using NHibernate.Tool.hbm2ddl;

namespace FastCloner.Tests;

using NHibernate;
using NHibernate.Proxy;

[TestFixture]
public class DbTests
{

private ISessionFactory sessionFactory;
private const string DbFile = "test.db";

[OneTimeSetUp]
public void SetUp()
{
// Smažeme existující databázi, pokud existuje
if (File.Exists(DbFile))
{
File.Delete(DbFile);
}

Configuration configuration = CreateConfiguration();
sessionFactory = configuration.BuildSessionFactory();

// Vytvoříme schéma databáze
using (ISession? session = sessionFactory.OpenSession())
{
SchemaExport export = new SchemaExport(configuration);
export.Execute(true, true, false, session.Connection, null);
}
}

[OneTimeTearDown]
public void TearDown()
{
sessionFactory?.Dispose();

if (File.Exists(DbFile))
{
File.Delete(DbFile);
}
}

private static Configuration CreateConfiguration()
{
return Fluently.Configure()
.Database(SQLiteConfiguration.Standard
.ConnectionString($"Data Source={DbFile};Version=3;")
.ShowSql())
.Mappings(m => m.FluentMappings
.Add<EntityMap>()
.Add<ChildEntityMap>())
.BuildConfiguration();
}

public class Entity
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<ChildEntity> Children { get; set; } = new List<ChildEntity>();
}

public class ChildEntity
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual Entity Entity { get; set; }
}

public class EntityMap : ClassMap<Entity>
{
public EntityMap()
{
Table("Entities"); // Změněno z "Entity"
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.Name);
HasMany(x => x.Children)
.Cascade.AllDeleteOrphan()
.Inverse()
.KeyColumn("EntityId");
}
}

public class ChildEntityMap : ClassMap<ChildEntity>
{
public ChildEntityMap()
{
Table("ChildEntities"); // Změněno z "ChildEntity"
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.Name);
References(x => x.Entity)
.Column("EntityId")
.Not.Nullable();
}
}

[Test]
public void Test_CloneNHibernateProxy()
{
using ISession? session = sessionFactory.OpenSession();
using ITransaction? transaction = session.BeginTransaction();
try
{
// Arrange
Entity entity = new Entity
{
Name = "Test"
};

ChildEntity child = new ChildEntity
{
Name = "Child1",
Entity = entity
};

entity.Children.Add(child);

session.Save(entity);
transaction.Commit();

// Act
Entity? loadedEntity = session.Load<Entity>(entity.Id);
Entity unproxiedEntity = NHibernateHelper.Unproxy(loadedEntity);
Entity cloned = unproxiedEntity.DeepClone();

// Assert
Assert.Multiple(() =>
{
Assert.That(cloned, Is.Not.Null);
Assert.That(cloned, Is.Not.InstanceOf<INHibernateProxy>());
Assert.That(cloned.Id, Is.EqualTo(entity.Id));
Assert.That(cloned.Name, Is.EqualTo("Test"));
Assert.That(cloned.Children, Has.Count.EqualTo(1));
Assert.That(cloned.Children[0].Name, Is.EqualTo("Child1"));
});
}
catch (Exception e)
{
transaction.Rollback();
throw;
}
}
}

public static class NHibernateHelper
{
public static T Unproxy<T>(T entity) where T : class
{
if (entity == null)
return null;

// Pokud je to proxy objekt
if (entity is INHibernateProxy proxy)
{
return (T)proxy.HibernateLazyInitializer.GetImplementation();
}

return entity;
}
}
23 changes: 17 additions & 6 deletions FastCloner.Tests/FastCloner.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,23 @@
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentValidation" Version="11.9.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
<PackageReference Include="NUnit" Version="4.0.1" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
<PackageReference Include="NUnit.Analyzers" Version="4.0.1" />
<PackageReference Include="coverlet.collector" Version="6.0.0" />
<PackageReference Include="FluentNHibernate" Version="3.4.0" />
<PackageReference Include="FluentValidation" Version="12.0.0-preview1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="NHibernate" Version="5.5.2" />
<PackageReference Include="NUnit" Version="4.3.2" />
<PackageReference Include="NUnit3TestAdapter" Version="5.0.0-beta.5" />
<PackageReference Include="NUnit.Analyzers" Version="4.5.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="System.Data.SqlClient" Version="4.9.0" />
<PackageReference Include="System.Data.SQLite" Version="1.0.119" />
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.119" />
<PackageReference Include="System.Drawing.Common" Version="8.0.3" />
</ItemGroup>

Expand Down
125 changes: 125 additions & 0 deletions FastCloner.Tests/SpecialCaseTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1053,6 +1053,131 @@ public void ExpandoObject_With_Collection_Clone()
});
}

[Test]
public void ReadOnlyDictionary_Clone_ShouldCreateNewInstance()
{
// Arrange
Dictionary<string, int> originalDict = new Dictionary<string, int> { ["One"] = 1, ["Two"] = 2 };
ReadOnlyDictionary<string, int> original = new ReadOnlyDictionary<string, int>(originalDict);

// Act
ReadOnlyDictionary<string, int>? cloned = FastCloner.DeepClone(original);

// Assert
Assert.Multiple(() =>
{
Assert.That(cloned, Is.Not.SameAs(original), "Should create new instance");
Assert.That(cloned, Is.TypeOf<ReadOnlyDictionary<string, int>>(), "Should preserve type");
Assert.That(cloned.Count, Is.EqualTo(original.Count), "Should have same count");
Assert.That(cloned["One"], Is.EqualTo(1), "Should preserve values");
Assert.That(cloned["Two"], Is.EqualTo(2), "Should preserve values");
});
}

[Test]
public void IReadOnlyDictionary_Clone_ShouldCreateNewInstance()
{
// Arrange
IReadOnlyDictionary<string, int> original =
new Dictionary<string, int> { ["One"] = 1, ["Two"] = 2 }.AsReadOnly();

// Act
IReadOnlyDictionary<string, int>? cloned = FastCloner.DeepClone(original);

// Assert
Assert.Multiple(() =>
{
Assert.That(cloned, Is.Not.SameAs(original), "Should create new instance");
Assert.That(cloned, Is.AssignableTo<IReadOnlyDictionary<string, int>>(), "Should preserve interface");
Assert.That(cloned.Count, Is.EqualTo(original.Count), "Should have same count");
Assert.That(cloned["One"], Is.EqualTo(1), "Should preserve values");
Assert.That(cloned["Two"], Is.EqualTo(2), "Should preserve values");
});
}

[Test]
public void ReadOnlyDictionary_WithComplexValues_Clone_ShouldDeepClone()
{
// Arrange
Dictionary<string, List<string>> originalDict = new Dictionary<string, List<string>>
{
["List1"] = ["A", "B"],
["List2"] = ["C", "D"]
};
ReadOnlyDictionary<string, List<string>> original = new ReadOnlyDictionary<string, List<string>>(originalDict);

// Act
ReadOnlyDictionary<string, List<string>>? cloned = FastCloner.DeepClone(original);

// Assert
Assert.Multiple(() =>
{
Assert.That(cloned, Is.Not.SameAs(original), "Should create new instance");
Assert.That(cloned["List1"], Is.Not.SameAs(original["List1"]), "Should deep clone values");
Assert.That(cloned["List2"], Is.Not.SameAs(original["List2"]), "Should deep clone values");
Assert.That(cloned["List1"], Is.EquivalentTo(original["List1"]), "Should preserve value contents");
Assert.That(cloned["List2"], Is.EquivalentTo(original["List2"]), "Should preserve value contents");
});
}

[Test]
public void ReadOnlyDictionary_WithNullValues_Clone_ShouldPreserveNulls()
{
// Arrange
Dictionary<string, string> originalDict = new Dictionary<string, string>
{
["NotNull"] = "Value",
["Null"] = null
};
ReadOnlyDictionary<string, string> original = new ReadOnlyDictionary<string, string>(originalDict);

// Act
ReadOnlyDictionary<string, string>? cloned = FastCloner.DeepClone(original);

// Assert
Assert.Multiple(() =>
{
Assert.That(cloned["NotNull"], Is.EqualTo("Value"), "Should preserve non-null values");
Assert.That(cloned["Null"], Is.Null, "Should preserve null values");
});
}

[Test]
public void ReadOnlyDictionary_Empty_Clone_ShouldCreateEmptyInstance()
{
// Arrange
ReadOnlyDictionary<string, int> original = new ReadOnlyDictionary<string, int>(new Dictionary<string, int>());

// Act
ReadOnlyDictionary<string, int>? cloned = FastCloner.DeepClone(original);

// Assert
Assert.Multiple(() =>
{
Assert.That(cloned, Is.Not.SameAs(original), "Should create new instance");
Assert.That(cloned.Count, Is.EqualTo(0), "Should be empty");
});
}

[Test]
public void ReadOnlyDictionary_WithKeyValuePairs_Clone_ShouldPreserveEnumeration()
{
// Arrange
Dictionary<int, string> originalDict = new Dictionary<int, string> { [1] = "One", [2] = "Two" };
ReadOnlyDictionary<int, string> original = new ReadOnlyDictionary<int, string>(originalDict);

// Act
ReadOnlyDictionary<int, string>? cloned = FastCloner.DeepClone(original);

// Assert
Assert.Multiple(() =>
{
Assert.That(cloned.Keys, Is.EquivalentTo(original.Keys), "Should preserve keys");
Assert.That(cloned.Values, Is.EquivalentTo(original.Values), "Should preserve values");
Assert.That(cloned, Is.EquivalentTo(original), "Should preserve key-value pairs");
});
}

[Test]
public void ExpandoObject_With_Circular_Reference_Clone()
{
Expand Down
Loading

0 comments on commit 924a8a0

Please sign in to comment.