[corlib] Disable ThreadLocalTests.DisposeOnThreadExit on MonoTouch, it's randomly...
[mono.git] / mcs / class / corlib / Test / System.Threading / ThreadLocalTests.cs
1 // 
2 // ThreadLazyTests.cs
3 //  
4 // Author:
5 //       Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
6 // 
7 // Copyright (c) 2009 Jérémie "Garuma" Laval
8 // 
9 // Permission is hereby granted, free of charge, to any person obtaining a copy
10 // of this software and associated documentation files (the "Software"), to deal
11 // in the Software without restriction, including without limitation the rights
12 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 // copies of the Software, and to permit persons to whom the Software is
14 // furnished to do so, subject to the following conditions:
15 // 
16 // The above copyright notice and this permission notice shall be included in
17 // all copies or substantial portions of the Software.
18 // 
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 // THE SOFTWARE.
26
27 using System;
28 using System.Threading;
29
30 using NUnit;
31 using NUnit.Framework;
32 #if !MOBILE
33 using NUnit.Framework.SyntaxHelpers;
34 #endif
35
36 namespace MonoTests.System.Threading
37 {
38         [TestFixtureAttribute]
39         public class ThreadLocalTests
40         {
41                 ThreadLocal<int> threadLocal;
42                 int nTimes;
43                 
44                 [SetUp]
45                 public void Setup ()
46                 {
47                         nTimes = 0;
48                         threadLocal = new ThreadLocal<int> (() => { Interlocked.Increment (ref nTimes); return 42; });
49                 }
50
51                 [Test]
52                 public void SingleThreadTest ()
53                 {
54                         AssertThreadLocal ();
55                 }
56                 
57                 [Test]
58                 public void ThreadedTest ()
59                 {
60                         AssertThreadLocal ();
61                         
62                         Thread t = new Thread ((object o) => { Interlocked.Decrement (ref nTimes); AssertThreadLocal (); });
63                         t.Start ();
64                         t.Join ();
65                 }
66
67                 [Test]
68                 public void InitializeThrowingTest ()
69                 {
70                         int callTime = 0;
71                         threadLocal = new ThreadLocal<int> (() => {
72                                         Interlocked.Increment (ref callTime);
73                                         throw new ApplicationException ("foo");
74                                 });
75
76                         Exception exception = null;
77
78                         try {
79                                 var foo = threadLocal.Value;
80                         } catch (Exception e) {
81                                 exception = e;
82                         }
83
84                         Assert.IsNotNull (exception, "#1");
85                         Assert.That (exception, Is.TypeOf (typeof (ApplicationException)), "#2");
86                         Assert.AreEqual (1, callTime, "#3");
87
88                         exception = null;
89
90                         try {
91                                 var foo = threadLocal.Value;
92                         } catch (Exception e) {
93                                 exception = e;
94                         }
95
96                         Assert.IsNotNull (exception, "#4");
97                         Assert.That (exception, Is.TypeOf (typeof (ApplicationException)), "#5");
98                         Assert.AreEqual (2, callTime, "#6");
99                 }
100
101                 [Category ("NotDotNet")] // nunit results in stack overflow
102                 public void MultipleReferenceToValueTest ()
103                 {
104                         try {
105                                 threadLocal = new ThreadLocal<int> (() => threadLocal.Value + 1);
106                                 var v = threadLocal.Value;
107
108                                 Assert.Fail ("#1");
109                         } catch (InvalidOperationException e) {
110                         }
111                 }
112
113                 [Test]
114                 public void DefaultThreadLocalInitTest ()
115                 {
116                         var local = new ThreadLocal<DateTime> ();
117                         var local2 = new ThreadLocal<object> ();
118
119                         Assert.AreEqual (default (DateTime), local.Value);
120                         Assert.AreEqual (default (object), local2.Value);
121                 }
122
123                 [Test, ExpectedException (typeof (ObjectDisposedException))]
124                 public void DisposedOnValueTest ()
125                 {
126                         var tl = new ThreadLocal<int> ();
127                         tl.Dispose ();
128                         var value = tl.Value;
129                 }
130
131                 [Test, ExpectedException (typeof (ObjectDisposedException))]
132                 public void DisposedOnIsValueCreatedTest ()
133                 {
134                         var tl = new ThreadLocal<int> ();
135                         tl.Dispose ();
136                         var value = tl.IsValueCreated;
137                 }
138
139                 [Test]
140                 public void PerThreadException ()
141                 {
142                         int callTime = 0;
143                         threadLocal = new ThreadLocal<int> (() => {
144                                         if (callTime == 1)
145                                                 throw new ApplicationException ("foo");
146                                         Interlocked.Increment (ref callTime);
147                                         return 43;
148                                 });
149
150                         Exception exception = null;
151
152                         var foo = threadLocal.Value;
153                         bool thread_value_created = false;
154                         Assert.AreEqual (43, foo, "#3");
155                         Thread t = new Thread ((object o) => {
156                                 try {
157                                         var foo2 = threadLocal.Value;
158                                 } catch (Exception e) {
159                                         exception = e;
160                                 }
161                                 // should be false and not throw
162                                 thread_value_created = threadLocal.IsValueCreated;
163                         });
164                         t.Start ();
165                         t.Join ();
166                         Assert.AreEqual (false, thread_value_created, "#4");
167                         Assert.IsNotNull (exception, "#5");
168                         Assert.That (exception, Is.TypeOf (typeof (ApplicationException)), "#6");
169                 }
170
171                 void AssertThreadLocal ()
172                 {
173                         Assert.IsFalse (threadLocal.IsValueCreated, "#1");
174                         Assert.AreEqual (42, threadLocal.Value, "#2");
175                         Assert.IsTrue (threadLocal.IsValueCreated, "#3");
176                         Assert.AreEqual (42, threadLocal.Value, "#4");
177                         Assert.AreEqual (1, nTimes, "#5");
178                 }
179
180                 class SetMreOnFinalize
181                 {
182                         ManualResetEventSlim m_mres;
183
184                         public SetMreOnFinalize (ManualResetEventSlim mres)
185                         {
186                                 m_mres = mres;
187                         }
188
189                         ~SetMreOnFinalize()
190                         {
191                                 m_mres.Set();
192                         }
193                 }
194
195                 [Test]
196                 [Category ("NotWorking")] // Finalizers aren't guaranteed
197 #if MONOTOUCH
198                 [Category ("NotWorking")] // https://bugzilla.xamarin.com/show_bug.cgi?id=34617
199 #endif
200                 public void DisposeOnThreadExit ()
201                 {
202                         var threadLocal = new ThreadLocal<SetMreOnFinalize>();
203                         var mres = new ManualResetEventSlim(false);
204                         var thread = new Thread (() => { threadLocal.Value = new SetMreOnFinalize (mres); });
205
206                         thread.Start ();
207                         thread.Join ();
208
209                         SpinWait.SpinUntil (() => {
210                                 GC.Collect();
211                                 GC.WaitForPendingFinalizers();
212                                 GC.Collect();
213                                 return mres.IsSet;
214                         }, 500);
215
216                         if (!mres.IsSet)
217                                 Assert.Fail ("Finalizer didn't run after thread termination");
218                 }
219         }
220 }