Merge pull request #3135 from kumpera/enable_conc_gc_on_mainline_archs
[mono.git] / mcs / class / System / Test / System.Timers / TimerTest.cs
1 //
2 // TimerTest.cs - NUnit Test Cases for System.Timers.Timer
3 //
4 // Author:
5 //   Kornél Pál <http://www.kornelpal.hu/>
6 //   Robert Jordan <robertj@gmx.net>
7 //
8 // Copyright (C) 2005 Kornél Pál
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using NUnit.Framework;
33 using System;
34 using System.Timers;
35 using ST = System.Threading;
36
37 namespace MonoTests.System.Timers
38 {
39         [TestFixture]
40         public class TimerTest
41         {
42                 Timer timer;
43
44                 [SetUp]
45                 public void SetUp ()
46                 {
47                         timer = new Timer ();
48                 }
49
50                 [TearDown]
51                 public void TearDown ()
52                 {
53                         timer.Close ();
54                 }
55
56                 [Test]
57                 public void Constructor0 ()
58                 {
59                         Assert.IsTrue (timer.AutoReset, "#1");
60                         Assert.IsFalse (timer.Enabled, "#2");
61                         Assert.AreEqual (100, timer.Interval, "#3");
62                         Assert.IsNull (timer.SynchronizingObject, "#4");
63                 }
64
65                 [Test]
66                 public void Constructor1 ()
67                 {
68                         timer = new Timer (1);
69                         Assert.IsTrue (timer.AutoReset, "#A1");
70                         Assert.IsFalse (timer.Enabled, "#A2");
71                         Assert.AreEqual (1, timer.Interval, "#A3");
72                         Assert.IsNull (timer.SynchronizingObject, "#A4");
73
74                         timer = new Timer (int.MaxValue);
75                         Assert.IsTrue (timer.AutoReset, "#B1");
76                         Assert.IsFalse (timer.Enabled, "#B2");
77                         Assert.AreEqual (int.MaxValue, timer.Interval, "#B3");
78                         Assert.IsNull (timer.SynchronizingObject, "#B4");
79                 }
80
81                 [Test]
82                 public void Constructor1_Interval_Negative ()
83                 {
84                         try {
85                                 new Timer (-1);
86                                 Assert.Fail ("#1");
87                         } catch (ArgumentException ex) {
88                                 // Invalid value -1 for parameter interval
89                                 Assert.AreEqual (typeof (ArgumentException), ex.GetType (), "#2");
90                                 Assert.IsNull (ex.InnerException, "#3");
91                                 Assert.IsNotNull (ex.Message, "#4");
92                         }
93                 }
94
95                 [Test]
96                 public void Constructor1_Interval_Zero ()
97                 {
98                         try {
99                                 new Timer (0);
100                                 Assert.Fail ("#1");
101                         } catch (ArgumentException ex) {
102                                 // Invalid value 0 for parameter interval
103                                 Assert.AreEqual (typeof (ArgumentException), ex.GetType (), "#2");
104                                 Assert.IsNull (ex.InnerException, "#3");
105                                 Assert.IsNotNull (ex.Message, "#4");
106                         }
107                 }
108
109                 [Test]
110                 public void Constructor1_Interval_Max ()
111                 {
112                         try {
113                                 new Timer (0x80000000);
114                                 Assert.Fail ("#A1");
115                         } catch (ArgumentException ex) {
116                                 // Invalid value 2147483648 for parameter interval
117                                 Assert.AreEqual (typeof (ArgumentException), ex.GetType (), "#A2");
118                                 Assert.IsNull (ex.InnerException, "#A3");
119                                 Assert.IsNotNull (ex.Message, "#A4");
120                         }
121
122                         try {
123                                 new Timer (double.MaxValue);
124                                 Assert.Fail ("#B1");
125                         } catch (ArgumentException ex) {
126                                 // Invalid value 1.79769313486232E+308 for parameter interval
127                                 Assert.AreEqual (typeof (ArgumentException), ex.GetType (), "#B2");
128                                 Assert.IsNull (ex.InnerException, "#B3");
129                                 Assert.IsNotNull (ex.Message, "#B4");
130                         }
131                 }
132
133                 [Test]
134                 [ExpectedException (typeof (ArgumentException))]
135                 public void Constructor1_Interval_Max_2 ()
136                 {
137                         timer = new Timer (double.MaxValue);
138                 }
139
140                 [Test]
141                 [ExpectedException (typeof (ArgumentException))]
142                 public void Constructor1_Interval_Min_1 ()
143                 {
144                         timer = new Timer (0);
145                 }
146
147                 [Test]
148                 [ExpectedException (typeof (ArgumentException))]
149                 public void Constructor1_Interval_Min_2 ()
150                 {
151                         timer = new Timer (-5);
152                 }
153
154                 [Test]
155                 public void Interval_TooHigh_Disabled_NoThrow ()
156                 {
157                         timer.Interval = double.MaxValue;
158                         Assert.AreEqual (double.MaxValue, timer.Interval, "#3");
159                 }
160
161                 [Test]
162                 public void Interval_TooHigh_ThrowOnEnabled ()
163                 {
164                         timer.Interval = 0x80000000;
165                         Assert.AreEqual (0x80000000, timer.Interval, "#1");
166                         try {
167                                 timer.Enabled = true;
168                                 Assert.Fail ("#2");
169                         } catch (Exception ex) {
170                                 Assert.AreEqual (typeof (ArgumentOutOfRangeException), ex.GetType (), "#3");
171                                 Assert.IsTrue (timer.Enabled);
172                         }
173                 }
174
175                 [Test]
176                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
177                 public void Interval_TooHigh_Enabled_Throw ()
178                 {
179                         timer.Interval = 100;
180                         timer.Enabled = true;
181                         timer.Interval = double.MaxValue;
182                 }
183
184                 [Test]
185                 public void DoubleClose_NoThrow ()
186                 {
187                         timer.Interval = 100;
188                         timer.Start ();
189                         timer.Close ();
190                         timer.Close ();
191                 }
192
193                 [Test]
194                 public void DisposedMeansDisabled_NoThrow ()
195                 {
196                         timer.Interval = 100;
197                         timer.Start ();
198                         timer.Close ();
199                         Assert.IsFalse (timer.Enabled);
200                 }
201
202                 [Test]
203                 public void Disposed_ThrowOnEnabled ()
204                 {
205                         timer.Interval = 100;
206                         timer.Start ();
207                         timer.Close ();
208                         timer.Enabled = false;
209                 }
210
211                 [Test]
212                 public void Elapsed_DontFireIfDisposed ()
213                 {
214                         timer.Interval = 500;
215                         var countElapsedCalls = 0;
216                         timer.Elapsed += (_, __) => { countElapsedCalls++; };
217                         timer.Start ();
218                         timer.Close ();
219                         ST.Thread.Sleep (500);
220                         Assert.AreEqual (countElapsedCalls, 0);
221                 }
222
223                 [Test]
224                 public void AutoReset ()
225                 {
226                         Assert.IsTrue (timer.AutoReset, "#1");
227                         timer.AutoReset = false;
228                         Assert.IsFalse (timer.AutoReset, "#2");
229                 }
230
231                 [Test]
232                 public void Interval ()
233                 {
234                         timer.Interval = 1;
235                         Assert.AreEqual (1, timer.Interval, "#1");
236                         timer.Interval = 500;
237                         Assert.AreEqual (500, timer.Interval, "#2");
238                         timer.Interval = double.MaxValue;
239                         Assert.AreEqual (double.MaxValue, timer.Interval, "#3");
240                 }
241
242                 [Test]
243                 public void Interval_Negative ()
244                 {
245                         try {
246                                 timer.Interval = -1;
247                                 Assert.Fail ("#1");
248                         } catch (ArgumentException ex) {
249                                 // '0' is not a valid value for 'Interval'. 'Interval' must be greater than 0
250                                 Assert.AreEqual (typeof (ArgumentException), ex.GetType (), "#2");
251                                 Assert.IsNull (ex.InnerException, "#3");
252                                 Assert.IsNotNull (ex.Message, "#4");
253                         }
254                 }
255
256                 [Test]
257                 public void Interval_Zero ()
258                 {
259                         try {
260                                 timer.Interval = 0;
261                                 Assert.Fail ("#1");
262                         } catch (ArgumentException ex) {
263                                 // '0' is not a valid value for 'Interval'. 'Interval' must be greater than 0
264                                 Assert.AreEqual (typeof (ArgumentException), ex.GetType (), "#2");
265                                 Assert.IsNull (ex.InnerException, "#3");
266                                 Assert.IsNotNull (ex.Message, "#4");
267                         }
268                 }
269
270                 [Test]
271                 public void StartStopEnabled ()
272                 {
273                         timer.Start ();
274                         Assert.IsTrue (timer.Enabled, "#1");
275                         timer.Stop ();
276                         Assert.IsFalse (timer.Enabled, "#2");
277                 }
278
279                 [Test]
280                 public void CloseEnabled ()
281                 {
282                         Assert.IsFalse (timer.Enabled, "#1");
283                         timer.Enabled = true;
284                         Assert.IsTrue (timer.Enabled, "#2");
285                         timer.Close ();
286                         Assert.IsFalse (timer.Enabled, "#3");
287                 }
288
289                 [Test] // bug https://bugzilla.novell.com/show_bug.cgi?id=325368
290                 public void EnabledInElapsed ()
291                 {
292                         var elapsedCount = 0;
293                         var mre = new ST.ManualResetEventSlim ();
294                         timer = new Timer (50);
295                         timer.AutoReset = false;
296                         timer.Elapsed += (s, e) =>
297                         {
298                                 elapsedCount++;
299                                 if (elapsedCount == 1)
300                                         timer.Enabled = true;
301                                 else if (elapsedCount == 2)
302                                         mre.Set ();
303                         };
304                         timer.Start ();
305
306                         Assert.IsTrue (mre.Wait (500), "#1 re-enabling timer in Elapsed didn't work");
307                         Assert.AreEqual (2, elapsedCount, "#2 wrong elapsedCount");
308                         timer.Stop ();
309                 }
310
311                 [Test]
312                 public void AutoResetEventFalseStopsFiringElapsed ()
313                 {
314                         var elapsedCount = 0;
315                         var mre = new ST.ManualResetEventSlim ();
316                         timer = new Timer (50);
317                         timer.AutoReset = false;
318                         timer.Elapsed += (s, e) =>
319                         {
320                                 elapsedCount++;
321                                 if (elapsedCount > 1)
322                                         mre.Set ();
323                         };
324                         timer.Start ();
325
326                         Assert.IsFalse (mre.Wait (500), "#1 AutoResetEvent=false didn't stop firing Elapsed, elapsedCount=" + elapsedCount);
327                         Assert.AreEqual (1, elapsedCount, "#2 wrong elapsedCount");
328                         timer.Stop ();
329                 }
330
331                 [Test]
332                 public void TestRaceCondition ()
333                 {
334                         Assert.IsTrue (new RaceTest (true).Success, "#1");
335                         Assert.IsTrue (new RaceTest (false).Success, "#2");
336                 }
337         }
338
339         class RaceTest
340         {
341                 const int Threads = 2;
342                 const int Loops = 100;
343
344                 object locker = new object ();
345                 Timer timer;
346                 int counter;
347
348                 public bool Success {
349                         get { return counter > Loops * Threads; }
350                 }
351
352                 public RaceTest (bool autoReset)
353                 {
354                         timer = new Timer ();
355                         timer.AutoReset = autoReset;
356                         timer.Interval = 100;
357                         timer.Elapsed += new ElapsedEventHandler (Tick);
358                         timer.Start ();
359
360                         ST.Thread[] tl = new ST.Thread [Threads];
361
362                         for (int i = 0; i < Threads; i++) {
363                                 tl [i] = new ST.Thread (new ST.ThreadStart (Run));
364                                 tl [i].Start ();
365                         }
366
367                         for (int i = 0; i < Threads; i++) {
368                                 tl [i].Join ();
369                         }
370
371                         ST.Thread.Sleep (1000);
372                 }
373
374                 void Restart ()
375                 {
376                         lock (locker) {
377                                 timer.Stop ();
378                                 timer.Start ();
379                         }
380                         ST.Interlocked.Increment (ref counter);
381                 }
382
383                 void Tick (object sender, ElapsedEventArgs e)
384                 {
385                         Restart ();
386                 }
387
388                 void Run ()
389                 {
390                         for (int i = 0; i < Loops; i++) {
391                                 ST.Thread.Sleep (0);
392                                 Restart ();
393                         }
394                 }
395         }
396 }