0
|
1 using System;
|
|
2
|
|
3 using NUnit.Framework;
|
|
4
|
|
5 using BLToolkit.Patterns;
|
|
6
|
|
7 namespace Patterns
|
|
8 {
|
|
9 [TestFixture]
|
|
10 public class DuckTypingTest
|
|
11 {
|
|
12 public interface TestInterface
|
|
13 {
|
|
14 int Method(int value);
|
|
15 void Method(int v1, out int v2);
|
|
16
|
|
17 int Prop { get; }
|
|
18
|
|
19 event EventHandler Event;
|
|
20
|
|
21 void CallEvent();
|
|
22 }
|
|
23
|
|
24 public interface TestInterface2
|
|
25 {
|
|
26 int Method(int value);
|
|
27 void I2Method(int v1, out int v2);
|
|
28 }
|
|
29
|
|
30 public class TestClass
|
|
31 {
|
|
32 public static int Field;
|
|
33
|
|
34 public int Method(int value)
|
|
35 {
|
|
36 return value + 2;
|
|
37 }
|
|
38
|
|
39 public void Method(int v1, out int v2)
|
|
40 {
|
|
41 v2 = v1;
|
|
42 }
|
|
43
|
|
44 public void I2Method(int v1, out int v2)
|
|
45 {
|
|
46 v2 = v1;
|
|
47 }
|
|
48
|
|
49 public int Prop
|
|
50 {
|
|
51 get { return 22; }
|
|
52 }
|
|
53
|
|
54 public event EventHandler Event;
|
|
55
|
|
56 public void CallEvent()
|
|
57 {
|
|
58 Event(this, EventArgs.Empty);
|
|
59 }
|
|
60 }
|
|
61
|
|
62 [Test]
|
|
63 public void Test()
|
|
64 {
|
|
65 var duck = DuckTyping.Implement<TestInterface> (new TestClass());
|
|
66 var same = DuckTyping.Implement<TestInterface> (duck);
|
|
67 var duck2 = DuckTyping.Implement<TestInterface2>(same);
|
|
68
|
|
69 Assert.AreSame(duck, same);
|
|
70
|
|
71 int value;
|
|
72 duck.Method(33, out value);
|
|
73
|
|
74 Assert.AreEqual(33, value);
|
|
75 Assert.AreEqual(42, duck.Method(40));
|
|
76 Assert.AreEqual(22, duck.Prop);
|
|
77
|
|
78 duck.Event += duck_Event;
|
|
79
|
|
80 duck.CallEvent();
|
|
81
|
|
82 Assert.AreEqual(55, eventValue);
|
|
83
|
|
84 duck2.I2Method(33, out value);
|
|
85
|
|
86 Assert.AreEqual(33, value);
|
|
87 Assert.AreEqual(42, duck2.Method(40));
|
|
88 }
|
|
89
|
|
90 int eventValue;
|
|
91
|
|
92 void duck_Event(object sender, EventArgs e)
|
|
93 {
|
|
94 eventValue = 55;
|
|
95 }
|
|
96
|
|
97 public class Child1 : TestClass
|
|
98 {
|
|
99 public new int Method(int value)
|
|
100 {
|
|
101 return value + 5;
|
|
102 }
|
|
103 }
|
|
104
|
|
105 public class Child2 : TestClass
|
|
106 {
|
|
107 public new int Method(int value)
|
|
108 {
|
|
109 return value + 10;
|
|
110 }
|
|
111 }
|
|
112
|
|
113 [Test]
|
|
114 public void BulkTest()
|
|
115 {
|
|
116 var ducks = DuckTyping.Implement<TestInterface,TestClass>(new Child1(), new Child2());
|
|
117
|
|
118 Assert.IsNotEmpty(ducks);
|
|
119 Assert.AreEqual(42, ducks[0].Method(40));
|
|
120 Assert.AreEqual(42, ducks[1].Method(40));
|
|
121 }
|
|
122
|
|
123 [Test]
|
|
124 public void BulkTest2()
|
|
125 {
|
|
126 var ducks = DuckTyping.Implement<TestInterface>(new Child1(), new Child2());
|
|
127
|
|
128 Assert.IsNotEmpty(ducks);
|
|
129 Assert.AreEqual(45, ducks[0].Method(40));
|
|
130 Assert.AreEqual(50, ducks[1].Method(40));
|
|
131 }
|
|
132
|
|
133 [Test]
|
|
134 public void InheritanceTest()
|
|
135 {
|
|
136 var duck1 = DuckTyping.Implement<TestInterface>(new Child1());
|
|
137 var duck2 = DuckTyping.Implement<TestInterface>(new Child2());
|
|
138
|
|
139 Assert.AreNotSame(duck1, duck2);
|
|
140 Assert.AreEqual(45, duck1.Method(40));
|
|
141 Assert.AreEqual(50, duck2.Method(40));
|
|
142 }
|
|
143
|
|
144 [Test]
|
|
145 public void InheritanceTest2()
|
|
146 {
|
|
147 var duck1 = DuckTyping.Implement<TestInterface,TestClass>(new Child1());
|
|
148 var duck2 = DuckTyping.Implement<TestInterface,TestClass>(new Child2());
|
|
149
|
|
150 Assert.AreNotSame(duck1, duck2);
|
|
151 Assert.AreEqual(42, duck1.Method(40));
|
|
152 Assert.AreEqual(42, duck2.Method(40));
|
|
153 }
|
|
154
|
|
155 public class StaticClass
|
|
156 {
|
|
157 public static int Method(int value)
|
|
158 {
|
|
159 return value + 3;
|
|
160 }
|
|
161 }
|
|
162
|
|
163 [Test]
|
|
164 public void StaticTest()
|
|
165 {
|
|
166 DuckTyping.AllowStaticMembers = true;
|
|
167
|
|
168 var duck = DuckTyping.Implement<TestInterface,StaticClass>(new StaticClass());
|
|
169
|
|
170 Assert.AreEqual(43, duck.Method(40));
|
|
171 }
|
|
172
|
|
173 public struct TestStruct
|
|
174 {
|
|
175 public int Method(int value)
|
|
176 {
|
|
177 return value + 3;
|
|
178 }
|
|
179 }
|
|
180
|
|
181 [Test]
|
|
182 public void StructTest()
|
|
183 {
|
|
184 DuckTyping.AllowStaticMembers = true;
|
|
185
|
|
186 var duck = DuckTyping.Implement<TestInterface>(new TestStruct());
|
|
187
|
|
188 Assert.AreEqual(43, duck.Method(40));
|
|
189 }
|
|
190
|
|
191
|
|
192 public interface GenericInterface<T>
|
|
193 {
|
|
194 T Method(T value);
|
|
195 }
|
|
196
|
|
197 public class GenericClass<T>
|
|
198 {
|
|
199 public T Method(T value)
|
|
200 {
|
|
201 return value;
|
|
202 }
|
|
203
|
|
204 public void I2Method(int v1, out int v2)
|
|
205 {
|
|
206 v2 = v1 + 2;
|
|
207 }
|
|
208 }
|
|
209
|
|
210 [Test]
|
|
211 public void GenericInterfaceTest()
|
|
212 {
|
|
213 var o = new GenericClass<int>();
|
|
214 var duck = DuckTyping.Implement<GenericInterface<int>>(o);
|
|
215 var duck2 = DuckTyping.Implement<TestInterface2> (o);
|
|
216
|
|
217 Assert.AreEqual(40, duck .Method(40));
|
|
218 Assert.AreEqual(40, duck2.Method(40));
|
|
219
|
|
220 int value;
|
|
221 duck2.I2Method (33, out value);
|
|
222 Assert.AreEqual(35, value);
|
|
223 }
|
|
224
|
|
225 [Test, ExpectedException(typeof(ArgumentNullException))]
|
|
226 public void InvalidArgTest1()
|
|
227 {
|
|
228 TestInterface o = null;
|
|
229
|
|
230 var duck1 = DuckTyping.Implement<TestInterface>(o);
|
|
231 var duck2 = (TestInterface)DuckTyping.Implement(typeof(TestInterface), o);
|
|
232 }
|
|
233
|
|
234 interface NonPublicInterface
|
|
235 {
|
|
236 }
|
|
237
|
|
238 [Test, ExpectedException(typeof(ArgumentException))]
|
|
239 public void InvalidArgTest2()
|
|
240 {
|
|
241 var duck = (NonPublicInterface)DuckTyping.Implement(typeof(NonPublicInterface), new TestClass());
|
|
242 }
|
|
243
|
|
244 [Test, ExpectedException(typeof(ArgumentException))]
|
|
245 public void InvalidArgTest3()
|
|
246 {
|
|
247 var duck = (Child1)DuckTyping.Implement(typeof(Child1), new Child2());
|
|
248 }
|
|
249
|
|
250 [Test, ExpectedException(typeof(ArgumentException))]
|
|
251 public void InvalidArgTest4()
|
|
252 {
|
|
253 var duck = (TestInterface)DuckTyping.Implement(typeof(TestInterface), typeof(TestInterface), new TestClass());
|
|
254 }
|
|
255
|
|
256 #region Aggregate
|
|
257
|
|
258 public interface IAggregatable
|
|
259 {
|
|
260 int Method1();
|
|
261 int Method2();
|
|
262 }
|
|
263
|
|
264 public interface IClass1
|
|
265 {
|
|
266 int Method1();
|
|
267 int Method3();
|
|
268 }
|
|
269
|
|
270 public interface IClass2
|
|
271 {
|
|
272 int Method2();
|
|
273 }
|
|
274
|
|
275 public class AggregateClass1: IClass1
|
|
276 {
|
|
277 public int Method1() { return 1; }
|
|
278 public int Method3() { return 3; }
|
|
279 }
|
|
280
|
|
281 public class AggregateClass2: IClass2
|
|
282 {
|
|
283 public int Method2() { return 2; }
|
|
284 }
|
|
285
|
|
286 [Test]
|
|
287 public void AggregateTest()
|
|
288 {
|
|
289 var duck = DuckTyping.Aggregate<IAggregatable>(new AggregateClass1(), new AggregateClass2());
|
|
290
|
|
291 Assert.IsNotNull(duck);
|
|
292
|
|
293 Assert.AreEqual(1, duck.Method1());
|
|
294 Assert.AreEqual(2, duck.Method2());
|
|
295
|
|
296 // It is still possible to get access
|
|
297 // to an interface of an underlying object.
|
|
298 //
|
|
299 var cls2 = DuckTyping.Implement<IClass2>(duck);
|
|
300
|
|
301 Assert.IsNotNull(cls2);
|
|
302 Assert.AreEqual(2, cls2.Method2());
|
|
303
|
|
304 // Even to switch from one aggregated object to another
|
|
305 //
|
|
306 var cls1 = DuckTyping.Implement<IClass1>(cls2);
|
|
307
|
|
308 Assert.IsNotNull(cls1);
|
|
309 Assert.AreEqual(1, cls1.Method1());
|
|
310 Assert.AreEqual(3, cls1.Method3());
|
|
311 }
|
|
312
|
|
313 [Test]
|
|
314 public void MissedMethodsAggregateTest()
|
|
315 {
|
|
316 var duck = DuckTyping.Aggregate<IClass1>(new Version(1,0), Guid.NewGuid());
|
|
317
|
|
318 Assert.That(duck, Is.Not.Null);
|
|
319
|
|
320 // Neither System.Guid nor System.Version will ever have Method1.
|
|
321 //
|
|
322 Assert.That(duck.Method1(), Is.EqualTo(0));
|
|
323 }
|
|
324
|
|
325 #endregion
|
|
326 }
|
|
327 }
|