Skip to content

Commit 91ec795

Browse files
committedMar 26, 2017
NH-3957: fix 2nd level query cache bug and test cases
1 parent c608d78 commit 91ec795

7 files changed

+158
-11
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
using System.Collections.Generic;
2+
using System.Reflection;
3+
using NHibernate.Transform;
4+
using NUnit.Framework;
5+
6+
namespace NHibernate.Test.NHSpecificTest.NH3957
7+
{
8+
[TestFixture]
9+
public class ResultTransformerEqualityFixture
10+
{
11+
/// <summary>
12+
/// Allows to simulate a hashcode collision. Issue would be unpractical to test otherwise.
13+
/// Hashcode collision must be supported for avoiding unexpected and hard to reproduce failures.
14+
/// </summary>
15+
private void TweakHashcode(System.Type transformerToTweak, object hasher)
16+
{
17+
var hasherTargetField = transformerToTweak.GetField("Hasher", BindingFlags.Static | BindingFlags.NonPublic);
18+
if (!_hasherBackup.ContainsKey(transformerToTweak))
19+
_hasherBackup.Add(transformerToTweak, hasherTargetField.GetValue(null));
20+
21+
// Though hasher is a readonly field, this works at the time of this writing. If it starts breaking and cannot be fixed,
22+
// ignore those tests or throw them away.
23+
hasherTargetField.SetValue(null, hasher);
24+
}
25+
26+
private Dictionary<System.Type, object> _hasherBackup = new Dictionary<System.Type, object>();
27+
28+
[SetUp]
29+
public void Setup()
30+
{
31+
var hasherForAll = typeof(AliasToEntityMapResultTransformer)
32+
.GetField("Hasher", BindingFlags.Static | BindingFlags.NonPublic)
33+
.GetValue(null);
34+
TweakHashcode(typeof(DistinctRootEntityResultTransformer), hasherForAll);
35+
TweakHashcode(typeof(PassThroughResultTransformer), hasherForAll);
36+
TweakHashcode(typeof(RootEntityResultTransformer), hasherForAll);
37+
TweakHashcode(typeof(ToListResultTransformer), hasherForAll);
38+
}
39+
40+
[TearDown]
41+
public void TearDown()
42+
{
43+
// Restore those types hashcode. (Avoid impacting perf of other tests, avoid second level query cache
44+
// issues if it was holding cached entries (but would mean some tests have not cleaned up properly).)
45+
foreach(var backup in _hasherBackup)
46+
{
47+
TweakHashcode(backup.Key, backup.Value);
48+
}
49+
}
50+
51+
// Non reg test case
52+
[Test]
53+
public void AliasToEntityMapEquality()
54+
{
55+
var transf1 = new AliasToEntityMapResultTransformer();
56+
var transf2 = new AliasToEntityMapResultTransformer();
57+
58+
Assert.IsTrue(transf1.Equals(transf2));
59+
Assert.IsTrue(transf2.Equals(transf1));
60+
}
61+
62+
[Test]
63+
public void AliasToEntityMapAndDistinctRootEntityInequality()
64+
{
65+
var transf1 = new AliasToEntityMapResultTransformer();
66+
var transf2 = new DistinctRootEntityResultTransformer();
67+
68+
Assert.IsFalse(transf1.Equals(transf2));
69+
Assert.IsFalse(transf2.Equals(transf1));
70+
}
71+
72+
// Non reg test case
73+
[Test]
74+
public void DistinctRootEntityEquality()
75+
{
76+
var transf1 = new DistinctRootEntityResultTransformer();
77+
var transf2 = new DistinctRootEntityResultTransformer();
78+
79+
Assert.IsTrue(transf1.Equals(transf2));
80+
Assert.IsTrue(transf2.Equals(transf1));
81+
}
82+
83+
// Non reg test case
84+
[Test]
85+
public void PassThroughEquality()
86+
{
87+
var transf1 = new PassThroughResultTransformer();
88+
var transf2 = new PassThroughResultTransformer();
89+
90+
Assert.IsTrue(transf1.Equals(transf2));
91+
Assert.IsTrue(transf2.Equals(transf1));
92+
}
93+
94+
[Test]
95+
public void PassThroughAndRootEntityInequality()
96+
{
97+
var transf1 = new PassThroughResultTransformer();
98+
var transf2 = new RootEntityResultTransformer();
99+
100+
Assert.IsFalse(transf1.Equals(transf2));
101+
Assert.IsFalse(transf2.Equals(transf1));
102+
}
103+
104+
// Non reg test case
105+
[Test]
106+
public void RootEntityEquality()
107+
{
108+
var transf1 = new RootEntityResultTransformer();
109+
var transf2 = new RootEntityResultTransformer();
110+
111+
Assert.IsTrue(transf1.Equals(transf2));
112+
Assert.IsTrue(transf2.Equals(transf1));
113+
}
114+
115+
[Test]
116+
public void RootEntityAndToListInequality()
117+
{
118+
var transf1 = new RootEntityResultTransformer();
119+
var transf2 = new ToListResultTransformer();
120+
121+
Assert.IsFalse(transf1.Equals(transf2));
122+
Assert.IsFalse(transf2.Equals(transf1));
123+
}
124+
125+
// Non reg test case
126+
[Test]
127+
public void ToListEquality()
128+
{
129+
var transf1 = new ToListResultTransformer();
130+
var transf2 = new ToListResultTransformer();
131+
132+
Assert.IsTrue(transf1.Equals(transf2));
133+
Assert.IsTrue(transf2.Equals(transf1));
134+
}
135+
}
136+
}

‎src/NHibernate.Test/NHibernate.Test.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -940,6 +940,7 @@
940940
<Compile Include="NHSpecificTest\NH3874\Two.cs" />
941941
<Compile Include="NHSpecificTest\NH3909\Entity.cs" />
942942
<Compile Include="NHSpecificTest\NH3909\FixtureByCode.cs" />
943+
<Compile Include="NHSpecificTest\NH3957\ResultTransformerEqualityFixture.cs" />
943944
<Compile Include="NHSpecificTest\NH646\Domain.cs" />
944945
<Compile Include="NHSpecificTest\NH646\Fixture.cs" />
945946
<Compile Include="NHSpecificTest\NH3234\Fixture.cs" />

‎src/NHibernate/Transform/AliasToEntityMapResultTransformer.cs

+5-3
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,20 @@ public override IList TransformList(IList collection)
3030
}
3131

3232

33-
public override bool IsTransformedValueATupleElement(String[] aliases, int tupleLength)
33+
public override bool IsTransformedValueATupleElement(string[] aliases, int tupleLength)
3434
{
3535
return false;
3636
}
3737

3838
public override bool Equals(object obj)
3939
{
40-
if (obj == null)
40+
if (obj == null || obj.GetHashCode() != Hasher.GetHashCode())
4141
{
4242
return false;
4343
}
44-
return obj.GetHashCode() == Hasher.GetHashCode();
44+
// NH-3957: do not rely on hashcode alone.
45+
// Must be the exact same type
46+
return obj.GetType() == typeof(AliasToEntityMapResultTransformer);
4547
}
4648

4749
public override int GetHashCode()

‎src/NHibernate/Transform/DistinctRootEntityResultTransformer.cs

+4-2
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,13 @@ public bool IsTransformedValueATupleElement(String[] aliases, int tupleLength)
7878

7979
public override bool Equals(object obj)
8080
{
81-
if (obj == null)
81+
if (obj == null || obj.GetHashCode() != Hasher.GetHashCode())
8282
{
8383
return false;
8484
}
85-
return obj.GetHashCode() == Hasher.GetHashCode();
85+
// NH-3957: do not rely on hashcode alone.
86+
// Must be the exact same type
87+
return obj.GetType() == typeof(DistinctRootEntityResultTransformer);
8688
}
8789

8890
public override int GetHashCode()

‎src/NHibernate/Transform/PassThroughResultTransformer.cs

+4-2
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,13 @@ internal object[] UntransformToTuple(object transformed, bool isSingleResult)
6161

6262
public override bool Equals(object obj)
6363
{
64-
if (obj == null)
64+
if (obj == null || obj.GetHashCode() != Hasher.GetHashCode())
6565
{
6666
return false;
6767
}
68-
return obj.GetHashCode() == Hasher.GetHashCode();
68+
// NH-3957: do not rely on hashcode alone.
69+
// Must be the exact same type
70+
return obj.GetType() == typeof(PassThroughResultTransformer);
6971
}
7072

7173
public override int GetHashCode()

‎src/NHibernate/Transform/RootEntityResultTransformer.cs

+4-2
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,13 @@ public bool[] IncludeInTransform(String[] aliases, int tupleLength)
4343

4444
public override bool Equals(object obj)
4545
{
46-
if (obj == null)
46+
if (obj == null || obj.GetHashCode() != Hasher.GetHashCode())
4747
{
4848
return false;
4949
}
50-
return obj.GetHashCode() == Hasher.GetHashCode();
50+
// NH-3957: do not rely on hashcode alone.
51+
// Must be the exact same type
52+
return obj.GetType() == typeof(RootEntityResultTransformer);
5153
}
5254

5355
public override int GetHashCode()

‎src/NHibernate/Transform/ToListResultTransformer.cs

+4-2
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,13 @@ public IList TransformList(IList list)
2525

2626
public override bool Equals(object obj)
2727
{
28-
if (obj == null)
28+
if (obj == null || obj.GetHashCode() != Hasher.GetHashCode())
2929
{
3030
return false;
3131
}
32-
return obj.GetHashCode() == Hasher.GetHashCode();
32+
// NH-3957: do not rely on hashcode alone.
33+
// Must be the exact same type
34+
return obj.GetType() == typeof(ToListResultTransformer);
3335
}
3436

3537
public override int GetHashCode()

0 commit comments

Comments
 (0)
Please sign in to comment.