Merge pull request #1066 from esdrubal/bug19313
[mono.git] / mcs / class / corlib / Test / System / LazyTest.cs
1 //
2 // LazyTest.cs - NUnit Test Cases for Lazy
3 //
4 // Author:
5 //      Zoltan Varga (vargaz@gmail.com)
6 //
7 // Copyright (C) 2009 Novell, Inc (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 #if NET_4_0
30
31 using System;
32 using System.Reflection;
33 using System.Threading;
34 using NUnit.Framework;
35
36 #pragma warning disable 219
37 #pragma warning disable 168
38
39 namespace MonoTests.System
40 {
41         [TestFixture]
42         public class LazyTest
43         {
44                 [Test]
45                 [ExpectedException (typeof (ArgumentNullException))]
46                 public void Ctor_Null_1 () {
47                         new Lazy<int> (null);
48                 }
49
50
51                 [Test]
52                 [ExpectedException (typeof (ArgumentNullException))]
53                 public void Ctor_Null_2 () {
54                         new Lazy<int> (null, false);
55                 }
56
57                 [Test]
58                 public void IsValueCreated () {
59                         var l1 = new Lazy<int> ();
60
61                         Assert.IsFalse (l1.IsValueCreated);
62
63                         int i = l1.Value;
64
65                         Assert.IsTrue (l1.IsValueCreated);
66                 }
67
68                 [Test]
69                 public void DefaultCtor () {
70                         var l1 = new Lazy<DefaultCtorClass> ();
71                         
72                         var o = l1.Value;
73                         Assert.AreEqual (5, o.Prop);
74                 }
75
76                 class DefaultCtorClass {
77                         public DefaultCtorClass () {
78                                 Prop = 5;
79                         }
80
81                         public int Prop {
82                                 get; set;
83                         }
84                 }
85
86                 [Test]
87                 public void NoDefaultCtor () {
88                         var l1 = new Lazy<NoDefaultCtorClass> ();
89                         
90                         try {
91                                 var o = l1.Value;
92                                 Assert.Fail ();
93                         } catch (MissingMemberException) {
94                         }
95                 }
96
97                 class NoDefaultCtorClass {
98                         public NoDefaultCtorClass (int i) {
99                         }
100                 }
101
102                 [Test]
103                 public void NotThreadSafe () {
104                         var l1 = new Lazy<int> ();
105
106                         Assert.AreEqual (0, l1.Value);
107
108                         var l2 = new Lazy<int> (delegate () { return 42; });
109
110                         Assert.AreEqual (42, l2.Value);
111                 }
112
113                 static int counter;
114
115                 [Test]
116                 public void EnsureSingleThreadSafeExecution () {
117                         counter = 42;
118
119                         var l = new Lazy<int> (delegate () { return counter ++; }, true);
120
121                         object monitor = new object ();
122                         var threads = new Thread [10];
123                         for (int i = 0; i < 10; ++i) {
124                                 threads [i] = new Thread (delegate () {
125                                                 lock (monitor) {
126                                                         Monitor.Wait (monitor);
127                                                 }
128                                                 int val = l.Value;
129                                         });
130                         }
131                         for (int i = 0; i < 10; ++i)
132                                 threads [i].Start ();
133                         lock (monitor)
134                                 Monitor.PulseAll (monitor);
135                         
136                         Assert.AreEqual (42, l.Value);
137                 }
138                 
139                 [Test]
140                 public void InitRecursion ()
141                 {
142                         Lazy<DefaultCtorClass> c = null;
143                         c = new Lazy<DefaultCtorClass> (() => { Console.WriteLine (c.Value); return null; });
144                         
145                         try {
146                                 var r = c.Value;
147                                 Assert.Fail ();
148                         } catch (InvalidOperationException) {
149                         }
150                 }
151
152                 [Test]
153                 public void ModeNone ()
154                 {
155                         int x;
156                         bool fail = true;
157                         Lazy<int> lz = new Lazy<int> (() => { if (fail) throw new Exception (); else return 99; }, LazyThreadSafetyMode.None);
158                         try {
159                                 x = lz.Value;
160                                 Assert.Fail ("#1");
161                                 Console.WriteLine (x);
162                         } catch (Exception ex) { }
163
164                         try {
165                                 x = lz.Value;
166                                 Assert.Fail ("#2");
167                         } catch (Exception ex) { }
168
169                         fail = false;
170                         try {
171                                 x = lz.Value;
172                                 Assert.Fail ("#3");
173                         } catch (Exception ex) { }
174
175                         bool rec = true;
176                         lz = new Lazy<int> (() => rec ? lz.Value : 99, LazyThreadSafetyMode.None);
177
178                         try {
179                                 x = lz.Value;
180                                 Assert.Fail ("#4");
181                         } catch (InvalidOperationException ex) { }
182
183                         rec = false;
184                         try {
185                                 x = lz.Value;
186                                 Assert.Fail ("#5");
187                         } catch (InvalidOperationException ex) { }
188                 }
189
190                 [Test]
191                 public void ModePublicationOnly () {
192                         bool fail = true;
193                         int invoke = 0;
194                         Lazy<int> lz = new Lazy<int> (() => { ++invoke; if (fail) throw new Exception (); else return 99; }, LazyThreadSafetyMode.PublicationOnly);
195
196                         try {
197                                 int x = lz.Value;
198                                 Assert.Fail ("#1");
199                                 Console.WriteLine (x);
200                         } catch (Exception ex) { }
201
202                         try {
203                                 int x = lz.Value;
204                                 Assert.Fail ("#2");
205                         } catch (Exception ex) { }
206
207
208                         Assert.AreEqual (2, invoke, "#3");
209                         fail = false;
210                         Assert.AreEqual (99,  lz.Value, "#4");
211                         Assert.AreEqual (3, invoke, "#5");
212
213                         invoke = 0;
214                         bool rec = true;
215                         lz = new Lazy<int> (() => { ++invoke; bool r = rec; rec = false; return r ? lz.Value : 88; },   LazyThreadSafetyMode.PublicationOnly);
216
217                         Assert.AreEqual (88,  lz.Value, "#6");
218                         Assert.AreEqual (2, invoke, "#7");
219                 }
220
221                 [Test]
222                 public void ModeExecutionAndPublication () {
223                         int invoke = 0;
224                         bool fail = true;
225                         Lazy<int> lz = new Lazy<int> (() => { ++invoke; if (fail) throw new Exception (); else return 99; }, LazyThreadSafetyMode.ExecutionAndPublication);
226
227                         try {
228                                 int x = lz.Value;
229                                 Assert.Fail ("#1");
230                                 Console.WriteLine (x);
231                         } catch (Exception ex) { }
232                         Assert.AreEqual (1, invoke, "#2");
233
234                         try {
235                                 int x = lz.Value;
236                                 Assert.Fail ("#3");
237                         } catch (Exception ex) { }
238                         Assert.AreEqual (1, invoke, "#4");
239
240                         fail = false;
241                         try {
242                                 int x = lz.Value;
243                                 Assert.Fail ("#5");
244                         } catch (Exception ex) { }
245                         Assert.AreEqual (1, invoke, "#6");
246
247                         bool rec = true;
248                         lz = new Lazy<int> (() => rec ? lz.Value : 99, LazyThreadSafetyMode.ExecutionAndPublication);
249
250                         try {
251                                 int x = lz.Value;
252                                 Assert.Fail ("#7");
253                         } catch (InvalidOperationException ex) { }
254
255                         rec = false;
256                         try {
257                                 int x = lz.Value;
258                                 Assert.Fail ("#8");
259                         } catch (InvalidOperationException ex) { }
260                 }
261
262                 static int Return22 () {
263                         return 22;
264                 }
265
266                 [Test]
267                 public void Trivial_Lazy () {
268                         var x = new Lazy<int> (Return22, false);
269                         Assert.AreEqual (22, x.Value, "#1");
270                 }
271
272                 [Test]
273                 public void ConcurrentInitialization ()
274                 {
275                         var init = new AutoResetEvent (false);
276                         var e1_set = new AutoResetEvent (false);
277
278                         var lazy = new Lazy<string> (() => {
279                                 init.Set ();
280                                 Thread.Sleep (10);
281                                 throw new ApplicationException ();
282                         });
283
284                         Exception e1 = null;
285                         var thread = new Thread (() => {
286                                 try {
287                                         string value = lazy.Value;
288                                 } catch (Exception ex) {
289                                         e1 = ex;
290                                         e1_set.Set ();
291                                 }
292                         });
293                         thread.Start ();
294
295                         Assert.IsTrue (init.WaitOne (3000), "#1");
296
297                         Exception e2 = null;
298                         try {
299                                 string value = lazy.Value;
300                         } catch (Exception ex) {
301                                 e2 = ex;
302                         }
303
304                         Exception e3 = null;
305                         try {
306                                 string value = lazy.Value;
307                         } catch (Exception ex) {
308                                 e3 = ex;
309                         }
310
311                         Assert.IsTrue (e1_set.WaitOne (3000), "#2");
312                         Assert.AreSame (e1, e2, "#3");
313                         Assert.AreSame (e1, e3, "#4");
314                 }
315
316         }
317 }
318
319 #endif