1
+ using System ;
2
+ using System . Collections ;
3
+ using System . Collections . Concurrent ;
4
+ using System . Collections . Generic ;
5
+ using System . Linq ;
6
+ using System . Reflection ;
7
+ using NHibernate . Linq ;
8
+ using NHibernate . Proxy ;
9
+ using NHibernate . Proxy . DynamicProxy ;
10
+ using NUnit . Framework ;
11
+
12
+ namespace NHibernate . Test . NHSpecificTest . NH3954
13
+ {
14
+ [ TestFixture ]
15
+ public class Fixture
16
+ {
17
+ private ProxyCache _cache ;
18
+ private ConcurrentDictionary < ProxyCacheEntry , System . Type > _internalCache ;
19
+ private static readonly FieldInfo InternalCacheField =
20
+ typeof ( ProxyCache ) . GetField ( "cache" , BindingFlags . Static | BindingFlags . NonPublic ) ;
21
+
22
+ [ SetUp ]
23
+ public void SetUp ( )
24
+ {
25
+ _cache = new ProxyCache ( ) ;
26
+
27
+ _internalCache = ( ConcurrentDictionary < ProxyCacheEntry , System . Type > ) InternalCacheField . GetValue ( _cache ) ;
28
+
29
+ _cache . StoreProxyType ( typeof ( Entity1FakeProxy ) , typeof ( Entity1 ) ) ;
30
+ _cache . StoreProxyType ( typeof ( Entity2FakeProxy ) , typeof ( Entity2 ) , typeof ( INHibernateProxy ) ) ;
31
+ _cache . StoreProxyType ( typeof ( Entity3FakeProxy ) , typeof ( Entity3 ) ) ;
32
+ _cache . StoreProxyType ( typeof ( Entity4FakeProxy ) , typeof ( Entity4 ) , typeof ( IProxy ) ) ;
33
+ _cache . StoreProxyType ( typeof ( Entity5FakeProxy ) , typeof ( Entity5 ) , typeof ( INHibernateProxy ) , typeof ( IProxy ) ) ;
34
+
35
+ // Artificially inject other entries with same hashcodes
36
+ Inject ( new ProxyCacheEntry ( typeof ( Entity1 ) , null ) , typeof ( Entity1FakeProxy2 ) , typeof ( Entity1 ) , typeof ( INHibernateProxy ) ) ;
37
+ Inject ( new ProxyCacheEntry ( typeof ( Entity1 ) , null ) , typeof ( Entity3FakeProxy2 ) , typeof ( Entity3 ) ) ;
38
+
39
+ Inject ( new ProxyCacheEntry ( typeof ( Entity2 ) , new [ ] { typeof ( INHibernateProxy ) } ) , typeof ( Entity2FakeProxy2 ) , typeof ( Entity2 ) ) ;
40
+ Inject ( new ProxyCacheEntry ( typeof ( Entity2 ) , new [ ] { typeof ( INHibernateProxy ) } ) , typeof ( Entity4FakeProxy2 ) , typeof ( Entity4 ) , typeof ( IProxy ) ) ;
41
+ Inject ( new ProxyCacheEntry ( typeof ( Entity2 ) , new [ ] { typeof ( INHibernateProxy ) } ) , typeof ( Entity5FakeProxy2 ) , typeof ( Entity5 ) , typeof ( INHibernateProxy ) , typeof ( IProxy ) ) ;
42
+ }
43
+
44
+ private void Inject ( ProxyCacheEntry entryToTweak , System . Type result , System . Type baseType , params System . Type [ ] baseInterfaces )
45
+ {
46
+ TweakEntry ( entryToTweak , baseType , baseInterfaces ) ;
47
+ _internalCache [ entryToTweak ] = result ;
48
+ }
49
+
50
+ private static readonly MethodInfo BaseTypeSetter = typeof ( ProxyCacheEntry ) . GetProperty ( "BaseType" ) . GetSetMethod ( true ) ;
51
+ private static readonly MethodInfo InterfacesSetter = typeof ( ProxyCacheEntry ) . GetProperty ( "Interfaces" ) . GetSetMethod ( true ) ;
52
+ private static readonly FieldInfo UniqueInterfacesField =
53
+ typeof ( ProxyCacheEntry ) . GetField ( "_uniqueInterfaces" , BindingFlags . Instance | BindingFlags . NonPublic ) ;
54
+
55
+ /// <summary>
56
+ /// Transforms the entry to some other one but preserves its hashcode. This allows to reproduce the issue, which otherwise
57
+ /// is too unlikely for being tested.
58
+ /// </summary>
59
+ private void TweakEntry ( ProxyCacheEntry entryToTweak , System . Type baseType , params System . Type [ ] baseInterfaces )
60
+ {
61
+ BaseTypeSetter . Invoke ( entryToTweak , new object [ ] { baseType } ) ;
62
+ InterfacesSetter . Invoke ( entryToTweak , new object [ ] { baseInterfaces ?? new System . Type [ 0 ] } ) ;
63
+ UniqueInterfacesField . SetValue ( entryToTweak , new HashSet < System . Type > ( baseInterfaces ?? new System . Type [ 0 ] ) ) ;
64
+ }
65
+
66
+ [ TearDown ]
67
+ public void TearDown ( )
68
+ {
69
+ _cache = null ;
70
+ _internalCache = null ;
71
+ }
72
+
73
+ [ Test ]
74
+ public void ProxyCacheEntity1FakeProxy ( )
75
+ {
76
+ var result = _cache . GetProxyType ( typeof ( Entity1 ) ) ;
77
+ Assert . AreEqual ( typeof ( Entity1FakeProxy ) , result ) ;
78
+ }
79
+
80
+ [ Test ]
81
+ public void ProxyCacheEntity1FakeProxy2 ( )
82
+ {
83
+ var entry = new ProxyCacheEntry ( typeof ( Entity1 ) , null ) ;
84
+ TweakEntry ( entry , typeof ( Entity1 ) , typeof ( INHibernateProxy ) ) ;
85
+ var result = _internalCache [ entry ] ;
86
+ Assert . AreEqual ( typeof ( Entity1FakeProxy2 ) , result ) ;
87
+ }
88
+
89
+ [ Test ]
90
+ public void ProxyCacheEntity2FakeProxy ( )
91
+ {
92
+ var result = _cache . GetProxyType ( typeof ( Entity2 ) , typeof ( INHibernateProxy ) ) ;
93
+ Assert . AreEqual ( typeof ( Entity2FakeProxy ) , result ) ;
94
+ }
95
+
96
+ [ Test ]
97
+ public void ProxyCacheEntity2FakeProxy2 ( )
98
+ {
99
+ var entry = new ProxyCacheEntry ( typeof ( Entity2 ) , new [ ] { typeof ( INHibernateProxy ) } ) ;
100
+ TweakEntry ( entry , typeof ( Entity2 ) ) ;
101
+ var result = _internalCache [ entry ] ;
102
+ Assert . AreEqual ( typeof ( Entity2FakeProxy2 ) , result ) ;
103
+ }
104
+
105
+ [ Test ]
106
+ public void ProxyCacheEntity3FakeProxy ( )
107
+ {
108
+ var result = _cache . GetProxyType ( typeof ( Entity3 ) ) ;
109
+ Assert . AreEqual ( typeof ( Entity3FakeProxy ) , result ) ;
110
+ }
111
+
112
+ [ Test ]
113
+ public void ProxyCacheEntity3FakeProxy2 ( )
114
+ {
115
+ var entry = new ProxyCacheEntry ( typeof ( Entity1 ) , null ) ;
116
+ TweakEntry ( entry , typeof ( Entity3 ) ) ;
117
+ var result = _internalCache [ entry ] ;
118
+ Assert . AreEqual ( typeof ( Entity3FakeProxy2 ) , result ) ;
119
+ }
120
+
121
+ [ Test ]
122
+ public void ProxyCacheEntity4FakeProxy ( )
123
+ {
124
+ var result = _cache . GetProxyType ( typeof ( Entity4 ) , typeof ( IProxy ) ) ;
125
+ Assert . AreEqual ( typeof ( Entity4FakeProxy ) , result ) ;
126
+ // Interfaces order voluntarily inverted.
127
+ }
128
+
129
+ [ Test ]
130
+ public void ProxyCacheEntity4FakeProxy2 ( )
131
+ {
132
+ var entry = new ProxyCacheEntry ( typeof ( Entity2 ) , new [ ] { typeof ( INHibernateProxy ) } ) ;
133
+ TweakEntry ( entry , typeof ( Entity4 ) , typeof ( IProxy ) ) ;
134
+ var result = _internalCache [ entry ] ;
135
+ Assert . AreEqual ( typeof ( Entity4FakeProxy2 ) , result ) ;
136
+ }
137
+
138
+ [ Test ]
139
+ public void ProxyCacheEntity5FakeProxy ( )
140
+ {
141
+ var result = _cache . GetProxyType ( typeof ( Entity5 ) , typeof ( IProxy ) , typeof ( INHibernateProxy ) ) ;
142
+ Assert . AreEqual ( typeof ( Entity5FakeProxy ) , result ) ;
143
+ }
144
+
145
+ [ Test ]
146
+ public void ProxyCacheEntity5FakeProxy2 ( )
147
+ {
148
+ var entry = new ProxyCacheEntry ( typeof ( Entity2 ) , new [ ] { typeof ( INHibernateProxy ) } ) ;
149
+ TweakEntry ( entry , typeof ( Entity5 ) , typeof ( IProxy ) , typeof ( INHibernateProxy ) ) ;
150
+ var result = _internalCache [ entry ] ;
151
+ Assert . AreEqual ( typeof ( Entity5FakeProxy2 ) , result ) ;
152
+ }
153
+
154
+ [ Test ]
155
+ public void ProxyCacheNone ( )
156
+ {
157
+ // Beware not testing the lookup failure of any combination, even tweaked, actually added in cache.
158
+ // (Otherwise the test may starts failing unexpectedly sometimes, as the original bug ...)
159
+ // This one was not added in anyway.
160
+ System . Type result ;
161
+ Assert . IsFalse ( _cache . TryGetProxyType ( typeof ( Entity2 ) , new [ ] { typeof ( IProxy ) } , out result ) ) ;
162
+ }
163
+ }
164
+ }
0 commit comments