bab1c5f36e988207cebe4eaf9702dd28f9155ceb
[mono.git] / mcs / class / corlib / Test / System / TimeSpanTest.cs
1 //
2 // TimeSpanTest.cs - NUnit Test Cases for the System.TimeSpan struct
3 //
4 // Authors:
5 //      Duco Fijma (duco@lorentz.xs4all.nl)
6 //      Sebastien Pouliot  <sebastien@ximian.com>
7 //
8 // (C) 2001 Duco Fijma
9 // Copyright (C) 2004 Novell (http://www.novell.com)
10 //
11
12 using NUnit.Framework;
13 using System;
14 using System.Globalization;
15 using System.Threading;
16
17 namespace MonoTests.System
18 {
19
20 [TestFixture]
21 public class TimeSpanTest {
22
23         private void Debug (TimeSpan ts) 
24         {
25                 Console.Out.WriteLine ("Days {0}", ts.Days);
26                 Console.Out.WriteLine ("Hours {0}", ts.Hours);
27                 Console.Out.WriteLine ("Minutes {0}", ts.Minutes);
28                 Console.Out.WriteLine ("Seconds {0}", ts.Seconds);
29                 Console.Out.WriteLine ("Milliseconds {0}", ts.Milliseconds);
30                 Console.Out.WriteLine ("Ticks {0}", ts.Ticks);
31         }
32
33         [Test]
34         public void TestCtors ()
35         {
36                 TimeSpan t1 = new TimeSpan (1234567890);
37
38                 Assert.AreEqual ("00:02:03.4567890", t1.ToString (), "A1");
39                 t1 = new TimeSpan (1,2,3);
40                 Assert.AreEqual ("01:02:03", t1.ToString (), "A2");
41                 t1 = new TimeSpan (1,2,3,4);
42                 Assert.AreEqual ("1.02:03:04", t1.ToString (), "A3");
43                 t1 = new TimeSpan (1,2,3,4,5);
44                 Assert.AreEqual ("1.02:03:04.0050000", t1.ToString (), "A4");
45                 t1 = new TimeSpan (-1,2,-3,4,-5);
46                 Assert.AreEqual ("-22:02:56.0050000", t1.ToString (), "A5");
47                 t1 = new TimeSpan (0,25,0,0,0);
48                 Assert.AreEqual ("1.01:00:00", t1.ToString (), "A6");
49     }
50
51         [Test]
52         [ExpectedException (typeof (ArgumentOutOfRangeException))]
53         public void DaysOverflow () 
54         {
55                 int days = (int) (Int64.MaxValue / TimeSpan.TicksPerDay) + 1;
56                 TimeSpan ts = new TimeSpan (days, 0, 0, 0, 0);
57         }
58
59         [Test]
60         [ExpectedException (typeof (ArgumentOutOfRangeException))]
61         public void TemporaryOverflow () 
62         {
63                 // calculating part of this results in overflow (days)
64                 // but the negative hours, minutes, seconds & ms correct this
65                 int days = (int) (Int64.MaxValue / TimeSpan.TicksPerDay) + 1;
66                 TimeSpan ts = new TimeSpan (days, Int32.MinValue, Int32.MinValue, Int32.MinValue, Int32.MinValue);
67                 Assert.AreEqual (10650320, ts.Days, "Days");
68                 Assert.AreEqual (0, ts.Hours, "Hours");
69                 Assert.AreEqual (14, ts.Minutes, "Minutes");
70                 Assert.AreEqual (28, ts.Seconds, "Seconds");
71                 Assert.AreEqual (352, ts.Milliseconds, "Milliseconds");
72                 Assert.AreEqual (9201876488683520000, ts.Ticks, "Ticks");
73         }
74
75         [Test]
76         [ExpectedException (typeof (ArgumentOutOfRangeException))]
77         public void NoOverflowInHoursMinsSecondsMS () 
78         {
79                 TimeSpan ts = new TimeSpan (0, Int32.MaxValue, Int32.MaxValue, Int32.MaxValue, Int32.MaxValue);
80                 Assert.AreEqual (24879, ts.Days, "Days");
81                 Assert.AreEqual (22, ts.Hours, "Hours");
82                 Assert.AreEqual (44, ts.Minutes, "Minutes");
83                 Assert.AreEqual (30, ts.Seconds, "Seconds");
84                 Assert.AreEqual (647, ts.Milliseconds, "Milliseconds");
85                 Assert.AreEqual (21496274706470000, ts.Ticks, "Ticks");
86         }
87
88         [Test]
89         [ExpectedException (typeof (ArgumentOutOfRangeException))]
90         public void MaxDays () 
91         {
92                 new TimeSpan (Int32.MaxValue, 0, 0, 0, 0);
93         }
94
95         [Test]
96         [ExpectedException (typeof (ArgumentOutOfRangeException))]
97         public void MinDays () 
98         {
99                 new TimeSpan (Int32.MinValue, 0, 0, 0, 0);
100         }
101
102         [Test]
103         [ExpectedException (typeof (ArgumentOutOfRangeException))]
104         public void MaxHours () 
105         {
106                 // LAMESPEC: the highest hours are "special"
107                 TimeSpan ts = new TimeSpan (0, Int32.MaxValue, 0, 0, 0);
108                 Assert.AreEqual (0, ts.Days, "Max-Days");
109                 Assert.AreEqual (-1, ts.Hours, "Max-Hours");
110                 Assert.AreEqual (0, ts.Minutes, "Max-Minutes");
111                 Assert.AreEqual (0, ts.Seconds, "Max-Seconds");
112                 Assert.AreEqual (0, ts.Milliseconds, "Max-Milliseconds");
113                 Assert.AreEqual (-36000000000, ts.Ticks, "Max-Ticks");
114
115                 ts = new TimeSpan (0, Int32.MaxValue - 596522, 0, 0, 0);
116                 Assert.AreEqual (-24855, ts.Days, "Days");
117                 Assert.AreEqual (-3, ts.Hours, "Hours");
118                 Assert.AreEqual (0, ts.Minutes, "Minutes");
119                 Assert.AreEqual (0, ts.Seconds, "Seconds");
120                 Assert.AreEqual (0, ts.Milliseconds, "Milliseconds");
121                 Assert.AreEqual (-21474828000000000, ts.Ticks, "Ticks");
122         }
123
124         [Test]
125         [ExpectedException (typeof (ArgumentOutOfRangeException))]
126         public void MaxHours_BreakPoint () 
127         {
128                 TimeSpan ts = new TimeSpan (0, Int32.MaxValue - 596523, 0, 0, 0);
129                 Assert.AreEqual (24855, ts.Days, "Days");
130                 Assert.AreEqual (2, ts.Hours, "Hours");
131                 Assert.AreEqual (28, ts.Minutes, "Minutes");
132                 Assert.AreEqual (16, ts.Seconds, "Seconds");
133                 Assert.AreEqual (0, ts.Milliseconds, "Milliseconds");
134                 Assert.AreEqual (21474808960000000, ts.Ticks, "Ticks");
135         }
136
137         [Test]
138         public void MinHours () 
139         {
140                 TimeSpan ts = new TimeSpan (0, -256204778, 0, 0, 0);
141                 Assert.AreEqual (-10675199, ts.Days, "Days");
142                 Assert.AreEqual (-2, ts.Hours, "Hours");
143                 Assert.AreEqual (0, ts.Minutes, "Minutes");
144                 Assert.AreEqual (0, ts.Seconds, "Seconds");
145                 Assert.AreEqual (0, ts.Milliseconds, "Milliseconds");
146                 Assert.AreEqual (-9223372008000000000, ts.Ticks, "Ticks");
147         }
148
149         [Test]
150         [ExpectedException (typeof (ArgumentOutOfRangeException))]
151         public void MinHours_BreakPoint () 
152         {
153                 TimeSpan ts = new TimeSpan (0, -2146887124, 0, 0, 0);
154                 Assert.AreEqual (-24855, ts.Days, "Days");
155                 Assert.AreEqual (-2, ts.Hours, "Hours");
156                 Assert.AreEqual (-28, ts.Minutes, "Minutes");
157                 Assert.AreEqual (-16, ts.Seconds, "Seconds");
158                 Assert.AreEqual (0, ts.Milliseconds, "Milliseconds");
159                 Assert.AreEqual (-21474808960000000, ts.Ticks, "Ticks");
160         }
161
162         [Test]
163         public void MaxMinutes () 
164         {
165                 TimeSpan ts;
166                 ts = new TimeSpan (0, 0, 256204778, 0, 0);
167                 Assert.AreEqual (177919, ts.Days, "Max-Days");
168                 Assert.AreEqual (23, ts.Hours, "Max-Hours");
169                 Assert.AreEqual (38, ts.Minutes, "Max-Minutes");
170                 Assert.AreEqual (0, ts.Seconds, "Max-Seconds");
171                 Assert.AreEqual (0, ts.Milliseconds, "Max-Milliseconds");
172                 Assert.AreEqual (153722866800000000, ts.Ticks, "Max-Ticks");
173         }
174
175         [Test]
176         [ExpectedException (typeof (ArgumentOutOfRangeException))]
177         public void MaxMinutes_BreakPoint () 
178         {
179                 TimeSpan ts = new TimeSpan (0, Int32.MaxValue - 35791394, 0, 0, 0);
180                 Assert.AreEqual (0, ts.Days, "Days");
181                 Assert.AreEqual (0, ts.Hours, "Hours");
182                 Assert.AreEqual (-52, ts.Minutes, "Minutes");
183                 Assert.AreEqual (0, ts.Seconds, "Seconds");
184                 Assert.AreEqual (0, ts.Milliseconds, "Milliseconds");
185                 Assert.AreEqual (-31200000000, ts.Ticks, "Ticks");
186         }
187
188         [Test]
189         public void MinMinutes () 
190         {
191                 TimeSpan ts;
192                 ts = new TimeSpan (0, 0, Int32.MinValue, 0, 0);
193                 Assert.AreEqual (-1491308, ts.Days, "Days");
194                 Assert.AreEqual (-2, ts.Hours, "Hours");
195                 Assert.AreEqual (-8, ts.Minutes, "Minutes");
196                 Assert.AreEqual (0, ts.Seconds, "Seconds");
197                 Assert.AreEqual (0, ts.Milliseconds, "Milliseconds");
198                 Assert.AreEqual (-1288490188800000000, ts.Ticks, "Ticks");
199         }
200
201         [Test]
202         public void MinMinutes_BreakPoint () 
203         {
204                 TimeSpan ts = new TimeSpan (0, 0, -2111692253, 0, 0);
205                 Assert.AreEqual (-1466452, ts.Days, "Days");
206                 Assert.AreEqual (-22, ts.Hours, "Hours");
207                 Assert.AreEqual (-53, ts.Minutes, "Minutes");
208                 Assert.AreEqual (-0, ts.Seconds, "Seconds");
209                 Assert.AreEqual (0, ts.Milliseconds, "Milliseconds");
210                 Assert.AreEqual (-1267015351800000000, ts.Ticks, "Ticks");
211         }
212
213         [Test]
214         public void MaxSeconds () 
215         {
216                 TimeSpan ts = new TimeSpan (0, 0, 0, Int32.MaxValue, 0);
217                 Assert.AreEqual (24855, ts.Days, "Days");
218                 Assert.AreEqual (3, ts.Hours, "Hours");
219                 Assert.AreEqual (14, ts.Minutes, "Minutes");
220                 Assert.AreEqual (7, ts.Seconds, "Seconds");
221                 Assert.AreEqual (0, ts.Milliseconds, "Milliseconds");
222                 Assert.AreEqual (21474836470000000, ts.Ticks, "Ticks");
223         }
224
225         [Test]
226         public void MinSeconds () 
227         {
228                 TimeSpan ts = new TimeSpan (0, 0, 0, Int32.MinValue, 0);
229                 Assert.AreEqual (-24855, ts.Days, "Days");
230                 Assert.AreEqual (-3, ts.Hours, "Hours");
231                 Assert.AreEqual (-14, ts.Minutes, "Minutes");
232                 Assert.AreEqual (-8, ts.Seconds, "Seconds");
233                 Assert.AreEqual (0, ts.Milliseconds, "Milliseconds");
234                 Assert.AreEqual (-21474836480000000, ts.Ticks, "Ticks");
235         }
236
237         [Test]
238         public void MaxMilliseconds () 
239         {
240                 TimeSpan ts = new TimeSpan (0, 0, 0, 0, Int32.MaxValue);
241                 Assert.AreEqual (24, ts.Days, "Days");
242                 Assert.AreEqual (20, ts.Hours, "Hours");
243                 Assert.AreEqual (31, ts.Minutes, "Minutes");
244                 Assert.AreEqual (23, ts.Seconds, "Seconds");
245                 Assert.AreEqual (647, ts.Milliseconds, "Milliseconds");
246                 Assert.AreEqual (21474836470000, ts.Ticks, "Ticks");
247         }
248
249         [Test]
250         public void MinMilliseconds () 
251         {
252                 TimeSpan ts = new TimeSpan (0, 0, 0, 0, Int32.MinValue);
253                 Assert.AreEqual (-24, ts.Days, "Days");
254                 Assert.AreEqual (-20, ts.Hours, "Hours");
255                 Assert.AreEqual (-31, ts.Minutes, "Minutes");
256                 Assert.AreEqual (-23, ts.Seconds, "Seconds");
257                 Assert.AreEqual (-648, ts.Milliseconds, "Milliseconds");
258                 Assert.AreEqual (-21474836480000, ts.Ticks, "Ticks");
259         }
260
261         [Test]
262         public void NegativeTimeSpan () 
263         {
264                 TimeSpan ts = new TimeSpan (-23, -59, -59);
265                 Assert.AreEqual (0, ts.Days, "Days");
266                 Assert.AreEqual (-23, ts.Hours, "Hours");
267                 Assert.AreEqual (-59, ts.Minutes, "Minutes");
268                 Assert.AreEqual (-59, ts.Seconds, "Seconds");
269                 Assert.AreEqual (0, ts.Milliseconds, "Milliseconds");
270                 Assert.AreEqual (-863990000000, ts.Ticks, "Ticks");
271         }
272
273         [Test]
274         public void TestProperties ()
275         {
276                 TimeSpan t1 = new TimeSpan (1,2,3,4,5);
277                 TimeSpan t2 = -t1;
278
279                 Assert.AreEqual (1, t1.Days, "A1");
280                 Assert.AreEqual (2, t1.Hours, "A2");
281                 Assert.AreEqual (3, t1.Minutes, "A3");
282                 Assert.AreEqual (4, t1.Seconds, "A4");
283                 Assert.AreEqual (5, t1.Milliseconds, "A5");
284                 Assert.AreEqual (-1, t2.Days, "A6");
285                 Assert.AreEqual (-2, t2.Hours, "A7");
286                 Assert.AreEqual (-3, t2.Minutes, "A8");
287                 Assert.AreEqual (-4, t2.Seconds, "A9");
288                 Assert.AreEqual (-5, t2.Milliseconds, "A10");
289         }
290
291         [Test]
292         public void TestAdd ()
293         {
294                 TimeSpan t1 = new TimeSpan (2,3,4,5,6);
295                 TimeSpan t2 = new TimeSpan (1,2,3,4,5);
296                 TimeSpan t3 = t1 + t2;
297                 TimeSpan t4 = t1.Add (t2);
298                 TimeSpan t5;
299                 bool exception;
300
301                 Assert.AreEqual (3, t3.Days, "A1");
302                 Assert.AreEqual (5, t3.Hours, "A2");
303                 Assert.AreEqual (7, t3.Minutes, "A3");
304                 Assert.AreEqual (9, t3.Seconds, "A4");
305                 Assert.AreEqual (11, t3.Milliseconds, "A5");
306                 Assert.AreEqual ("3.05:07:09.0110000", t4.ToString (), "A6");
307                 try
308                 {
309                         t5 = TimeSpan.MaxValue + new TimeSpan (1);                      
310                         exception = false;
311                 }
312                 catch (OverflowException)
313                 {
314                         exception = true;
315                 }
316                 Assert.IsTrue (exception, "A7");
317         }
318
319         [Test]
320         public void TestCompare ()
321         {
322                 TimeSpan t1 = new TimeSpan (-1);
323                 TimeSpan t2 = new TimeSpan (1);
324                 int res;
325                 bool exception;
326
327                 Assert.AreEqual (-1, TimeSpan.Compare (t1, t2), "A1");
328                 Assert.AreEqual (1, TimeSpan.Compare (t2, t1), "A2");
329                 Assert.AreEqual (0, TimeSpan.Compare (t2, t2), "A3");
330                 Assert.AreEqual (-1, TimeSpan.Compare (TimeSpan.MinValue, TimeSpan.MaxValue), "A4");
331                 Assert.AreEqual (-1, t1.CompareTo (t2), "A5");
332                 Assert.AreEqual (1, t2.CompareTo (t1), "A6");
333                 Assert.AreEqual (0, t2.CompareTo (t2), "A7");
334                 Assert.AreEqual (-1, TimeSpan.Compare (TimeSpan.MinValue, TimeSpan.MaxValue), "A8");
335
336                 Assert.AreEqual (1, TimeSpan.Zero.CompareTo (null), "A9");
337                 
338                 try
339                 {
340                         res = TimeSpan.Zero.CompareTo("");
341                         exception = false;      
342                 }
343                 catch (ArgumentException)
344                 {
345                         exception = true;
346                 }
347                 Assert.IsTrue (exception, "A10");
348
349                 Assert.AreEqual (false, t1 == t2, "A11");
350                 Assert.AreEqual (false, t1 > t2, "A12");
351                 Assert.AreEqual (false, t1 >= t2, "A13");
352                 Assert.AreEqual (true, t1 != t2, "A14");
353                 Assert.AreEqual (true, t1 < t2, "A15");
354                 Assert.AreEqual (true, t1 <= t2, "A16");
355         }
356
357         [Test]
358         [ExpectedException (typeof (OverflowException))]
359         public void NoNegateMinValue() {
360                 TimeSpan t1 = TimeSpan.MinValue.Negate ();
361         }
362
363         [Test]
364         public void TestNegateAndDuration ()
365         {
366                 TimeSpan t1;
367                 bool exception;
368
369                 Assert.AreEqual ("-00:00:00.0012345", new TimeSpan (12345).Negate ().ToString (), "A1");
370                 Assert.AreEqual ("00:00:00.0012345", new TimeSpan (-12345).Duration ().ToString (), "A2");
371                         
372                 try
373                 {
374                         t1 = TimeSpan.MinValue.Duration ();
375                         exception = false;
376                 }
377                 catch (OverflowException) {
378                         exception = true;
379                 }
380                 Assert.IsTrue (exception, "A4");
381
382                 Assert.AreEqual ("-00:00:00.0000077", (-(new TimeSpan (77))).ToString (), "A5");
383                 Assert.AreEqual ("00:00:00.0000077", (+(new TimeSpan(77))).ToString(), "A6");
384         }
385
386         [Test]
387         public void TestEquals ()
388         {
389                 TimeSpan t1 = new TimeSpan (1);
390                 TimeSpan t2 = new TimeSpan (2);
391                 string s = "justastring";
392
393                 Assert.AreEqual (true, t1.Equals (t1), "A1");
394                 Assert.AreEqual (false, t1.Equals (t2), "A2");
395                 Assert.AreEqual (false, t1.Equals (s), "A3");
396                 Assert.AreEqual (false, t1.Equals (null), "A4");
397                 Assert.AreEqual (true, TimeSpan.Equals (t1, t1), "A5");
398                 Assert.AreEqual (false, TimeSpan.Equals (t1, t2), "A6");
399                 Assert.AreEqual (false, TimeSpan.Equals (t1, null), "A7");
400                 Assert.AreEqual (false, TimeSpan.Equals (t1, s), "A8");
401                 Assert.AreEqual (false, TimeSpan.Equals (s, t2), "A9");
402                 Assert.AreEqual (true, TimeSpan.Equals (null, null), "A10");
403         }
404
405         [Test]
406         public void TestFromXXXX ()
407         {
408                 Assert.AreEqual ("12.08:16:48", TimeSpan.FromDays (12.345).ToString (), "A1");
409                 Assert.AreEqual ("12:20:42", TimeSpan.FromHours (12.345).ToString (), "A2");
410                 Assert.AreEqual ("00:12:20.7000000", TimeSpan.FromMinutes (12.345).ToString (), "A3");
411                 Assert.AreEqual ("00:00:12.3450000", TimeSpan.FromSeconds (12.345).ToString (), "A4");
412                 Assert.AreEqual ("00:00:00.0120000", TimeSpan.FromMilliseconds (12.345).ToString (), "A5");
413                 Assert.AreEqual ("00:00:00.0012345", TimeSpan.FromTicks (12345).ToString (), "A6");
414                 Assert.AreEqual ("-00:00:00.0010000", TimeSpan.FromMilliseconds (-0.5).ToString (), "A7");
415                 Assert.AreEqual ("00:00:00.0010000", TimeSpan.FromMilliseconds (0.5).ToString (), "A8");
416                 Assert.AreEqual ("-00:00:00.0030000", TimeSpan.FromMilliseconds (-2.5).ToString (), "A9");
417                 Assert.AreEqual ("00:00:00.0030000", TimeSpan.FromMilliseconds (2.5).ToString (), "A10");
418                 Assert.AreEqual ("00:00:00.0010000", TimeSpan.FromSeconds (0.0005).ToString (), "A11");
419         }
420
421         [Test]
422         [ExpectedException (typeof (OverflowException))]
423         public void FromDays_MinValue ()
424         {
425                 TimeSpan.FromDays (Double.MinValue);
426         }
427
428         [Test]
429         [ExpectedException (typeof (OverflowException))]
430         public void FromDays_MaxValue ()
431         {
432                 TimeSpan.FromDays (Double.MaxValue);
433         }
434
435         [Test]
436         [ExpectedException (typeof (ArgumentException))]
437         public void FromDays_NaN ()
438         {
439                 TimeSpan.FromDays (Double.NaN);
440         }
441
442         [Test]
443         [ExpectedException (typeof (OverflowException))]
444         public void FromDays_PositiveInfinity ()
445         {
446                 // LAMESPEC: Document to return TimeSpan.MaxValue
447                 Assert.AreEqual (TimeSpan.MaxValue, TimeSpan.FromDays (Double.PositiveInfinity));
448         }
449
450         [Test]
451         [ExpectedException (typeof (OverflowException))]
452         public void FromDays_NegativeInfinity ()
453         {
454                 // LAMESPEC: Document to return TimeSpan.MinValue
455                 Assert.AreEqual (TimeSpan.MinValue, TimeSpan.FromDays (Double.NegativeInfinity));
456         }
457
458         [Test]
459         [ExpectedException (typeof (OverflowException))]
460         public void FromHours_MinValue ()
461         {
462                 TimeSpan.FromHours (Double.MinValue);
463         }
464
465         [Test]
466         [ExpectedException (typeof (OverflowException))]
467         public void FromHours_MaxValue ()
468         {
469                 TimeSpan.FromHours (Double.MaxValue);
470         }
471
472         [Test]
473         [ExpectedException (typeof (ArgumentException))]
474         public void FromHours_NaN ()
475         {
476                 TimeSpan.FromHours (Double.NaN);
477         }
478
479         [Test]
480         [ExpectedException (typeof (OverflowException))]
481         public void FromHours_PositiveInfinity ()
482         {
483                 // LAMESPEC: Document to return TimeSpan.MaxValue
484                 Assert.AreEqual (TimeSpan.MaxValue, TimeSpan.FromHours (Double.PositiveInfinity));
485         }
486
487         [Test]
488         [ExpectedException (typeof (OverflowException))]
489         public void FromHours_NegativeInfinity ()
490         {
491                 // LAMESPEC: Document to return TimeSpan.MinValue
492                 Assert.AreEqual (TimeSpan.MinValue, TimeSpan.FromHours (Double.NegativeInfinity));
493         }
494
495         [Test]
496         [ExpectedException (typeof (OverflowException))]
497         public void FromMilliseconds_MinValue ()
498         {
499                 TimeSpan.FromMilliseconds (Double.MinValue);
500         }
501
502         [Test]
503         [ExpectedException (typeof (OverflowException))]
504         public void FromMilliseconds_MaxValue ()
505         {
506                 TimeSpan.FromMilliseconds (Double.MaxValue);
507         }
508
509         [Test]
510         [ExpectedException (typeof (ArgumentException))]
511         public void FromMilliseconds_NaN ()
512         {
513                 TimeSpan.FromMilliseconds (Double.NaN);
514         }
515
516         [Test]
517         [ExpectedException (typeof (OverflowException))]
518         public void FromMilliseconds_PositiveInfinity ()
519         {
520                 // LAMESPEC: Document to return TimeSpan.MaxValue
521                 Assert.AreEqual (TimeSpan.MaxValue, TimeSpan.FromMilliseconds (Double.PositiveInfinity));
522         }
523
524         [Test]
525         [ExpectedException (typeof (OverflowException))]
526         public void FromMilliseconds_NegativeInfinity ()
527         {
528                 // LAMESPEC: Document to return TimeSpan.MinValue
529                 Assert.AreEqual (TimeSpan.MinValue, TimeSpan.FromMilliseconds (Double.NegativeInfinity));
530         }
531
532         [Test]
533         [ExpectedException (typeof (OverflowException))]
534         public void FromMinutes_MinValue ()
535         {
536                 TimeSpan.FromMinutes (Double.MinValue);
537         }
538
539         [Test]
540         [ExpectedException (typeof (OverflowException))]
541         public void FromMinutes_MaxValue ()
542         {
543                 TimeSpan.FromMinutes (Double.MaxValue);
544         }
545
546         [Test]
547         [ExpectedException (typeof (ArgumentException))]
548         public void FromMinutes_NaN ()
549         {
550                 TimeSpan.FromMinutes (Double.NaN);
551         }
552
553         [Test]
554         [ExpectedException (typeof (OverflowException))]
555         public void FromMinutes_PositiveInfinity ()
556         {
557                 // LAMESPEC: Document to return TimeSpan.MaxValue
558                 Assert.AreEqual (TimeSpan.MaxValue, TimeSpan.FromMinutes (Double.PositiveInfinity));
559         }
560
561         [Test]
562         [ExpectedException (typeof (OverflowException))]
563         public void FromMinutes_NegativeInfinity ()
564         {
565                 // LAMESPEC: Document to return TimeSpan.MinValue
566                 Assert.AreEqual (TimeSpan.MinValue, TimeSpan.FromMinutes (Double.NegativeInfinity));
567         }
568
569         [Test]
570         [ExpectedException (typeof (OverflowException))]
571         public void FromSeconds_MinValue ()
572         {
573                 TimeSpan.FromSeconds (Double.MinValue);
574         }
575
576         [Test]
577         [ExpectedException (typeof (OverflowException))]
578         public void FromSeconds_MaxValue ()
579         {
580                 TimeSpan.FromSeconds (Double.MaxValue);
581         }
582
583         [Test]
584         [ExpectedException (typeof (ArgumentException))]
585         public void FromSeconds_NaN ()
586         {
587                 TimeSpan.FromSeconds (Double.NaN);
588         }
589
590         [Test]
591         [ExpectedException (typeof (OverflowException))]
592         public void FromSeconds_PositiveInfinity ()
593         {
594                 // LAMESPEC: Document to return TimeSpan.MaxValue
595                 Assert.AreEqual (TimeSpan.MaxValue, TimeSpan.FromSeconds (Double.PositiveInfinity));
596         }
597
598         [Test]
599         [ExpectedException (typeof (OverflowException))]
600         public void FromSeconds_NegativeInfinity ()
601         {
602                 // LAMESPEC: Document to return TimeSpan.MinValue
603                 Assert.AreEqual (TimeSpan.MinValue, TimeSpan.FromSeconds (Double.NegativeInfinity));
604         }
605
606         [Test]
607         public void TestGetHashCode ()
608         {
609                 Assert.AreEqual (77, new TimeSpan (77).GetHashCode (), "A1");
610         }
611
612         private void ParseHelper (string s, bool expectFormat, bool expectOverflow, string expect)
613         {
614                 bool formatException = false;
615                 bool overflowException = false;
616                 string result = "junk ";
617
618                 try {
619                         result =  TimeSpan.Parse (s).ToString ();
620                 }
621                 catch (OverflowException) {
622                         overflowException = true;
623                 }
624                 catch (FormatException) {
625                         formatException = true;
626                 }
627                 Assert.AreEqual (expectFormat, formatException, "A1 [" + s + "]");
628                 Assert.AreEqual (expectOverflow, overflowException, "A2 " + s + "]");
629
630                 if (!expectOverflow && !expectFormat) {
631                         Assert.AreEqual (expect, result, "A3 [" + s + "]");
632                 }
633         }
634
635         [Test]
636         public void TestParse ()
637         {
638                 ParseHelper (" 13:45:15 ",false, false, "13:45:15");
639                 ParseHelper (" -1:2:3 ", false, false, "-01:02:03");
640
641 #if NET_4_0
642                 // In 4.0 when the first part is out of range, it parses it as day.
643                 ParseHelper (" 25:11:12 ", false, false, "25.11:12:00");
644                 ParseHelper (" 24:11:12 ", false, false, "24.11:12:00");
645                 ParseHelper (" 23:11:12 ", false, false, "23:11:12");
646 #else
647                 ParseHelper (" 25:0:0 ",false, true, "dontcare");
648 #endif
649
650                 ParseHelper ("-21.23:59:59.9999999", false, false, "-21.23:59:59.9999999");
651                 ParseHelper ("10:12  ", false, false, "10:12:00");
652                 ParseHelper ("aaa", true, false, "dontcare");
653
654                 ParseHelper ("100000000000000.1:1:1", false, true, "dontcare");
655                 ParseHelper ("24:60:60", false, true, "dontcare");
656                 ParseHelper ("0001:0002:0003.12     ", false, false, "01:02:03.1200000");
657
658 #if NET_4_0
659                 // In 4.0 when a section has more than 7 digits an OverflowException is thrown.
660                 ParseHelper (" 1:2:3:12345678 ", false, true, "dontcare");
661 #else
662                 ParseHelper (" 1:2:3:12345678 ", true, false, "dontcare"); 
663 #endif
664
665 #if NET_4_0
666                 ParseHelper ("10:11:12:13", false, false, "10.11:12:13"); // Days using : instead of . as separator
667                 ParseHelper ("10.11", true, false, "dontcare"); // days+hours is invalid
668
669                 // Force the use of french culture -which is using a non common NumberDecimalSeparator-
670                 // as current culture, to show that the Parse method is *actually* being culture sensitive
671                 // *and* also keeping the compatibility with '.'
672                 CultureInfo french_culture = CultureInfo.GetCultureInfo ("fr-FR");
673                 CultureInfo prev_culture = CultureInfo.CurrentCulture;
674                 try {
675                         Thread.CurrentThread.CurrentCulture = french_culture;
676                         ParseHelper ("10:10:10,006", false, false, "10:10:10.0060000");
677                         ParseHelper ("10:10:10.006", false, false, "10:10:10.0060000");
678                 } finally {
679                         // restore culture
680                         Thread.CurrentThread.CurrentCulture = prev_culture;
681                 }
682 #endif
683
684                 ParseHelper ("00:00:00", false, false, "00:00:00");
685                 ParseHelper ("00:10:00", false, false, "00:10:00");
686         }
687
688         // LAMESPEC: timespan in documentation is wrong - hh:mm:ss isn't mandatory
689         [Test]
690         public void Parse_Days_WithoutColon () 
691         {
692                 TimeSpan ts = TimeSpan.Parse ("1");
693                 Assert.AreEqual (1, ts.Days, "Days");
694         }
695
696         [Test]
697         public void TestSubstract ()
698         {
699                 TimeSpan t1 = new TimeSpan (2,3,4,5,6);
700                 TimeSpan t2 = new TimeSpan (1,2,3,4,5);
701                 TimeSpan t3 = t1 - t2;
702                 TimeSpan t4 = t1.Subtract (t2);
703                 TimeSpan t5;
704                 bool exception;
705
706                 Assert.AreEqual ("1.01:01:01.0010000", t3.ToString (), "A1");
707                 Assert.AreEqual ("1.01:01:01.0010000", t4.ToString (), "A2");
708                 try {
709                         t5 = TimeSpan.MinValue - new TimeSpan (1);
710                         exception = false;
711                 }
712                 catch (OverflowException) {
713                         exception = true;
714                 }
715                 Assert.IsTrue (exception, "A3");
716         }
717
718         [Test]
719         public void TestToString () 
720         {
721                 TimeSpan t1 = new TimeSpan (1,2,3,4,5);
722                 TimeSpan t2 = -t1;
723                 
724                 Assert.AreEqual ("1.02:03:04.0050000", t1.ToString (), "A1");
725                 Assert.AreEqual ("-1.02:03:04.0050000", t2.ToString (), "A2");
726                 Assert.AreEqual ("10675199.02:48:05.4775807", TimeSpan.MaxValue.ToString (), "A3");
727                 Assert.AreEqual ("-10675199.02:48:05.4775808", TimeSpan.MinValue.ToString (), "A4");
728         }
729
730         [Test]
731         public void ToString_Constants () 
732         {
733                 Assert.AreEqual ("00:00:00", TimeSpan.Zero.ToString (), "Zero");
734                 Assert.AreEqual ("10675199.02:48:05.4775807", TimeSpan.MaxValue.ToString (), "MaxValue");
735                 Assert.AreEqual ("-10675199.02:48:05.4775808", TimeSpan.MinValue.ToString (), "MinValue");
736         }
737
738         [Test]
739         public void Parse_InvalidValuesAndFormat_ExceptionOrder () 
740         {
741                 // hours should be between 0 and 23 but format is also invalid (too many dots)
742                 // In 2.0 overflow as precedence over format, but not in 4.0
743 #if NET_4_0
744                 try {
745                         TimeSpan.Parse ("0.99.99.0");
746                         Assert.Fail ("#A1");
747                 } catch (FormatException) {
748                 }
749 #else
750                 try {
751                         TimeSpan.Parse ("0.99.99.0");
752                         Assert.Fail ("#A1");
753                 } catch (OverflowException) {
754                 }
755 #endif
756                 try {
757                         TimeSpan.Parse ("0.999999999999.99.0");
758                         Assert.Fail ("#A2");
759                 } catch (OverflowException) {
760                 }
761         }
762
763         [Test]
764         public void Parse_MinMaxValues () 
765         {
766                 Assert.AreEqual (TimeSpan.MaxValue, TimeSpan.Parse ("10675199.02:48:05.4775807"), "MaxValue");
767                 Assert.AreEqual (TimeSpan.MinValue, TimeSpan.Parse ("-10675199.02:48:05.4775808"), "MinValue");
768         }
769
770         [Test]
771         [ExpectedException (typeof (OverflowException))]
772         public void Parse_OverMaxValue() 
773         {
774                 TimeSpan.Parse ("10675199.02:48:05.4775808");
775         }
776
777         [Test]
778         [ExpectedException (typeof (OverflowException))]
779         public void Parse_UnderMinValue() 
780         {
781                 TimeSpan.Parse ("-10675199.02:48:05.4775809");
782         }
783
784         [Test]
785         public void ParseMissingSeconds ()
786         {
787                 // as seen in ML for http://resources.esri.com/arcgisserver/apis/silverlight/
788                 TimeSpan ts = TimeSpan.Parse ("0:0:.75");
789
790                 Assert.AreEqual (0, ts.Days, "Days");
791                 Assert.AreEqual (0, ts.Hours, "Hours");
792                 Assert.AreEqual (750, ts.Milliseconds, "Milliseconds");
793                 Assert.AreEqual (0, ts.Minutes, "Minutes");
794                 Assert.AreEqual (0, ts.Seconds, "Seconds");
795                 Assert.AreEqual (7500000, ts.Ticks, "Ticks");
796                 Assert.AreEqual (0.0000086805555555555555, ts.TotalDays, 0.00000000000000001, "TotalDays");
797                 Assert.AreEqual (0.00020833333333333332, ts.TotalHours, 0.00000000000000001, "TotalHours");
798                 Assert.AreEqual (750.0, ts.TotalMilliseconds, "TotalMilliseconds");
799                 Assert.AreEqual (0.0125, ts.TotalMinutes, "TotalMinutes");
800                 Assert.AreEqual (0.75, ts.TotalSeconds, "TotalSeconds");
801         }
802
803         // 'Ported' the Parse test to use TryParse
804         [Test]
805         public void TryParse ()
806         {
807                 TimeSpan result;
808
809                 Assert.AreEqual (true, TimeSpan.TryParse (" 13:45:15 ", out result), "#A1");
810                 Assert.AreEqual ("13:45:15", result.ToString (), "#A2");
811
812                 Assert.AreEqual (true, TimeSpan.TryParse (" -1:2:3 ", out result), "#B1");
813                 Assert.AreEqual ("-01:02:03", result.ToString (), "#B2");
814
815                 Assert.AreEqual (false, TimeSpan.TryParse ("aaa", out result), "#C2");
816
817                 Assert.AreEqual (true, TimeSpan.TryParse ("-21.23:59:59.9999999", out result), "#D1");
818                 Assert.AreEqual ("-21.23:59:59.9999999", result.ToString (), "#D2");
819
820                 Assert.AreEqual (false, TimeSpan.TryParse ("100000000000000.1:1:1", out result), "#E1");
821                 Assert.AreEqual (false, TimeSpan.TryParse ("24:60:60", out result), "#E2");
822
823 #if NET_4_0
824                 Assert.AreEqual (true, TimeSpan.TryParse ("0001:0002:0003.12     ", out result), "#F1");
825 #else
826                 Assert.AreEqual (true, TimeSpan.TryParse ("0001:0002:0003.12     ", out result), "#F1");
827                 Assert.AreEqual ("01:02:03.1200000", result.ToString (), "#F2");
828 #endif
829
830                 Assert.AreEqual (false, TimeSpan.TryParse (" 1:2:3:12345678 ", out result), "#G1");
831
832                 // Min and Max values
833                 Assert.AreEqual (true, TimeSpan.TryParse ("10675199.02:48:05.4775807", out result), "MaxValue#1");
834                 Assert.AreEqual (TimeSpan.MaxValue, result, "MaxValue#2");
835                 Assert.AreEqual (true, TimeSpan.TryParse ("-10675199.02:48:05.4775808", out result), "MinValue#1");
836                 Assert.AreEqual (TimeSpan.MinValue, result, "MinValue#2");
837
838 #if NET_4_0
839                 // Force the use of french culture -which is using a non common NumberDecimalSeparator-
840                 // as current culture, to show that the Parse method is *actually* being culture sensitive
841                 CultureInfo french_culture = CultureInfo.GetCultureInfo ("fr-FR");
842                 CultureInfo prev_culture = CultureInfo.CurrentCulture;
843                 result = new TimeSpan (0, 10, 10, 10, 6);
844                 try {
845                         Thread.CurrentThread.CurrentCulture = french_culture;
846                         Assert.AreEqual (true, TimeSpan.TryParse ("10:10:10,006", out result), "#CultureSensitive1");
847                         Assert.AreEqual ("10:10:10.0060000", result.ToString (), "#CultureSensitive2");
848                 } finally {
849                         // restore culture
850                         Thread.CurrentThread.CurrentCulture = prev_culture;
851                 }
852 #endif
853         }
854
855         [Test]
856         public void TryParseErrors ()
857         {
858                 TimeSpan result;
859
860                 Assert.AreEqual (false, TimeSpan.TryParse ("0.99.99.0", out result), "Format#1");
861                 Assert.AreEqual (false, TimeSpan.TryParse ("10675199.02:48:05.4775808", out result), "OverMaxValue");
862                 Assert.AreEqual (false, TimeSpan.TryParse ("-10675199.02:48:05.4775809", out result), "UnderMinValue");
863         }
864
865 #if NET_4_0
866         [Test]
867         public void TryParseOverloads ()
868         { 
869                 TimeSpan result;
870
871                 // We use fr-FR culture since its NumericDecimalSeparator is not the same used by
872                 // most cultures - including the invariant one.
873                 CultureInfo french_culture = CultureInfo.GetCultureInfo ("fr-FR");
874                 Assert.AreEqual (true, TimeSpan.TryParse ("11:50:50,006", french_culture, out result), "#A1");
875
876                 // LAMESPEC - msdn states that an instance of DateTimeFormatInfo is retrieved to
877                 // obtain culture sensitive information, but at least in the betas that's false
878                 DateTimeFormatInfo format_info = new DateTimeFormatInfo ();
879                 format_info.TimeSeparator = ";";
880                 Assert.AreEqual (false, TimeSpan.TryParse ("11;50;50", format_info, out result), "#B1");
881                 Assert.AreEqual (true, TimeSpan.TryParse ("11:50:50", format_info, out result), "#B2");
882         }
883
884         [Test]
885         public void ParseExact ()
886         {
887                 CultureInfo french_culture = CultureInfo.GetCultureInfo ("fr-FR");
888                 CultureInfo us_culture = CultureInfo.GetCultureInfo ("en-US");
889
890                 // At this point we are only missing the style bites and then we are
891                 // pretty much done with the standard formats.
892
893                 //
894                 // 'g' format - this is the short and culture sensitive format
895                 //
896                 string [] g_format = new string [] { "g" };
897                 ParseExactHelper ("12", g_format, false, false, "12.00:00:00");
898                 ParseExactHelper ("11:12", g_format, false, false, "11:12:00");
899                 ParseExactHelper ("-11:12", g_format, false, false, "-11:12:00");
900                 ParseExactHelper ("25:13", g_format, true, false, "dontcare");
901                 ParseExactHelper ("11:66", g_format, true, false, "dontcare"); // I'd have expected OverflowExc here
902                 ParseExactHelper ("11:12:13", g_format, false, false, "11:12:13");
903                 ParseExactHelper ("-11:12:13", g_format, false, false, "-11:12:13");
904                 ParseExactHelper ("10.11:12:13", g_format, true, false, "dontcare"); // this should work as well
905                 ParseExactHelper ("10.11:12:13", g_format, true, false, "dontcare", us_culture);
906                 ParseExactHelper ("10.11:12:13", g_format, true, false, "dontcare", CultureInfo.InvariantCulture);
907                 ParseExactHelper ("10:11:12:66", g_format, true, false, "dontcare");
908                 ParseExactHelper ("10:11:12:13", g_format, false, false, "10.11:12:13");
909                 ParseExactHelper ("11:12:13.6", g_format, false, false, "11:12:13.6000000", CultureInfo.InvariantCulture);
910                 ParseExactHelper ("11:12:13,6", g_format, false, false, "11:12:13.6000000", french_culture);
911                 ParseExactHelper ("10:11:12:13.6", g_format, false, false, "10.11:12:13.6000000", us_culture);
912                 ParseExactHelper (" 10:11:12:13.6 ", g_format, false, false, "10.11:12:13.6000000", us_culture);
913                 ParseExactHelper ("10:11", g_format, false, false, "10:11:00", null, TimeSpanStyles.None);
914                 ParseExactHelper ("10:11", g_format, false, false, "10:11:00", null, TimeSpanStyles.AssumeNegative); // no effect
915
916                 // 
917                 // G format
918                 //
919                 string [] G_format = new string [] { "G" };
920                 ParseExactHelper ("9:10:12", G_format, true, false, "dontcare");
921                 ParseExactHelper ("9:10:12.6", G_format, true, false, "dontcare");
922                 ParseExactHelper ("3.9:10:12", G_format, true, false, "dontcare");
923                 ParseExactHelper ("3.9:10:12.153", G_format, true, false, "dontcare"); // this should be valid...
924                 ParseExactHelper ("3:9:10:12.153", G_format, false, false, "3.09:10:12.1530000", us_culture);
925                 ParseExactHelper ("0:9:10:12.153", G_format, false, false, "09:10:12.1530000", us_culture);
926                 ParseExactHelper ("03:09:10:12.153", G_format, false, false, "3.09:10:12.1530000", us_culture);
927                 ParseExactHelper ("003:009:0010:0012.00153", G_format, false, false, "3.09:10:12.0015300", us_culture);
928                 ParseExactHelper ("3:9:10:66.153", G_format, true, false, "dontcare"); // seconds out of range
929                 ParseExactHelper ("3:9:10:12.153", G_format, true, false, "dontcare", french_culture); // fr-FR uses ',' as decimal separator
930                 ParseExactHelper ("3:9:10:12,153", G_format, false, false, "3.09:10:12.1530000", french_culture);
931                 ParseExactHelper ("  3:9:10:12.153  ", G_format, false, false, "3.09:10:12.1530000", us_culture);
932                 ParseExactHelper ("3:9:10:13.153", G_format, false, false, "3.09:10:13.1530000", us_culture, TimeSpanStyles.AssumeNegative);
933
934                 // c format
935                 string [] c_format = new string [] { "c" };
936                 ParseExactHelper ("12", c_format, false, false, "12.00:00:00");
937                 ParseExactHelper ("12:11", c_format, false, false, "12:11:00");
938                 ParseExactHelper ("12:66", c_format, true, false, "dontcare");
939                 ParseExactHelper ("10.11:12", c_format, false, false, "10.11:12:00");
940                 ParseExactHelper ("10.11:12:13", c_format, false, false, "10.11:12:13");
941                 ParseExactHelper ("10:11:12:13", c_format, true, false, "dontcare"); // this is normally accepted in the Parse method
942                 ParseExactHelper ("10.11:12:13.6", c_format, false, false, "10.11:12:13.6000000");
943                 ParseExactHelper ("10:11:12,6", c_format, true, false, "dontcare");
944                 ParseExactHelper ("10:11:12,6", c_format, true, false, "dontcare", french_culture);
945                 ParseExactHelper ("  10:11:12.6  ", c_format, false, false, "10:11:12.6000000");
946                 ParseExactHelper ("10:12", c_format, false, false, "10:12:00", null, TimeSpanStyles.AssumeNegative);
947                 ParseExactHelper ("10:123456789999", c_format, true, false, "dontcare");
948
949                 ParseExactHelper ("10:12", new string [0], true, false, "dontcare");
950                 ParseExactHelper ("10:12", new string [] { String.Empty }, true, false, "dontcare");
951                 ParseExactHelper ("10:12", new string [] { null }, true, false, "dontcare");
952         }
953
954         [Test]
955         public void ParseExactMultipleFormats ()
956         {
957                 ParseExactHelper ("10:12", new string [] { "G", "g" }, false, false, "10:12:00");
958                 ParseExactHelper ("10:12", new string [] { "g", "G" }, false, false, "10:12:00");
959                 ParseExactHelper ("7.8:9:10", new string [] { "G", "g" }, true, false, "dontcare");
960                 ParseExactHelper ("7.8:9:10", new string [] { "G", "g", "c" }, false, false, "7.08:09:10");
961                 ParseExactHelper ("7:8:9:10", new string [] { "c", "g" }, false, false, "7.08:09:10");
962                 ParseExactHelper ("7:8:9:10", new string [] { "c", "G" }, true, false, "dontcare");
963                 ParseExactHelper ("7.123456789:1", new string [] { "c", "G", "g" }, true, false, "dontcare");
964                 ParseExactHelper ("7.123456789:1", new string [] { "G", "g", "c" }, true, false, "dontcare");
965                 ParseExactHelper ("1234567890123456", new string [] { "c", "g" }, true, false, "dontcare"); // I'd expect an OverflowException
966                 ParseExactHelper ("10:12", new string [] { null, "c", "g" }, true, false, "10:12:00");
967                 ParseExactHelper ("10:12", new string [] { String.Empty, "c", "g" }, true, false, "10:12:00");
968         }
969
970         [Test]
971         public void ParseExactCustomFormats ()
972         {
973                 // Days
974                 ParseExactHelper ("33", new string [] { "%d" }, false, false, "33.00:00:00");
975                 ParseExactHelper ("00", new string [] { "%d" }, false, false, "00:00:00");
976                 ParseExactHelper ("33", new string [] { "%dd" }, false, false, "33.00:00:00");
977                 ParseExactHelper ("3333", new string [] { "%d" }, false, false, "3333.00:00:00");
978                 ParseExactHelper ("3333", new string [] { "%ddd" }, true, false, "3333.00:00:00"); // 'dd' mismatch the digit count
979                 ParseExactHelper ("3333", new string [] { "%dddd" }, false, false, "3333.00:00:00");
980                 ParseExactHelper ("00033", new string [] { "%ddddd" }, false, false, "33.00:00:00");
981                 ParseExactHelper ("00033", new string [] { "%d" }, false, false, "33.00:00:00");
982                 ParseExactHelper ("00000003", new string [] { "%dddddddd" }, false, false, "3.00:00:00"); // up to 8 'd'
983                 ParseExactHelper ("000000003", new string [] { "%ddddddddd" }, true, false, "dontcare");
984                 ParseExactHelper ("33", new string [] { "d" }, true, false, "33.00:00:00"); // This is sort of weird.
985                 ParseExactHelper ("33", new string [] { "dd" }, false, false, "33.00:00:00");
986                 ParseExactHelper ("-33", new string [] { "%d" }, true, false, "dontcare");
987                 ParseExactHelper ("33", new string [] { "%d" }, false, false, "-33.00:00:00", null, TimeSpanStyles.AssumeNegative);
988
989                 // Hours
990                 ParseExactHelper ("12", new string [] { "%h" }, false, false, "12:00:00");
991                 ParseExactHelper ("00", new string [] { "%h" }, false, false, "00:00:00");
992                 ParseExactHelper ("012", new string [] { "%h" }, true, false, "dontcare"); // more than 2 digits
993                 ParseExactHelper ("00012", new string [] { "%hhhhh" }, true, false, "dontcare");
994                 ParseExactHelper ("15", new string [] { "%h" }, false, false, "15:00:00");
995                 ParseExactHelper ("24", new string [] { "%h" }, true, false, "dontcare");
996                 ParseExactHelper ("15", new string [] { "%hh" }, false, false, "15:00:00");
997                 ParseExactHelper ("1", new string [] { "%hh" }, true, false, "dontcare"); // 'hh' but a single digit
998                 ParseExactHelper ("01", new string [] { "%hh" }, false, false, "01:00:00");
999                 ParseExactHelper ("015", new string [] { "%hhh" }, true, false, "dontcare"); // Too many 'h'
1000                 ParseExactHelper ("12", new string [] { "h" }, true, false, "dontcare");
1001                 ParseExactHelper ("12", new string [] { "hh" }, false, false, "12:00:00");
1002                 ParseExactHelper ("-15", new string [] {"%h"}, true, false, "dontcare"); // Explicit - not accepted
1003                 ParseExactHelper ("15", new string [] { "%h" }, false, false, "-15:00:00", null, TimeSpanStyles.AssumeNegative);
1004                 ParseExactHelper ("15", new string [] { "%H" }, true, false, "dontcare"); // Uppercase is not accepted
1005
1006                 // Minutes
1007                 ParseExactHelper ("12", new string [] { "%m" }, false, false, "00:12:00");
1008                 ParseExactHelper ("00", new string [] { "%m" }, false, false, "00:00:00");
1009                 ParseExactHelper ("60", new string [] { "%m" }, true, false, "dontcare");
1010                 ParseExactHelper ("12", new string [] { "%mm" }, false, false, "00:12:00");
1011                 ParseExactHelper ("1", new string [] { "%mm" }, true, false, "dontcare");
1012                 ParseExactHelper ("12", new string [] { "%mmm" }, true, false, "dontcare");
1013                 ParseExactHelper ("12", new string [] { "m" }, true, false, "dontcare");
1014                 ParseExactHelper ("12", new string [] { "mm" }, false, false, "00:12:00");
1015                 ParseExactHelper ("-12", new string [] { "%m" }, true, false, "dontcare");
1016                 ParseExactHelper ("12", new string [] { "%m" }, false, false, "-00:12:00", null, TimeSpanStyles.AssumeNegative);
1017                 ParseExactHelper ("12", new string [] { "%M" }, true, false, "dontcare");
1018
1019                 // Seconds
1020                 ParseExactHelper ("12", new string [] { "%s" }, false, false, "00:00:12");
1021                 ParseExactHelper ("00", new string [] { "%s" }, false, false, "00:00:00");
1022                 ParseExactHelper ("000", new string [] { "%s" }, true, false, "dontcare");
1023                 ParseExactHelper ("12", new string [] { "%ss" }, false, false, "00:00:12");
1024                 ParseExactHelper ("12", new string [] { "%sss" }, true, false, "dontcare");
1025                 ParseExactHelper ("60", new string [] { "%s" }, true, false, "dontcare");
1026                 ParseExactHelper ("-12", new string [] { "%s" }, true, false, "dontcare");
1027                 ParseExactHelper ("12", new string [] { "%s" }, false, false, "-00:00:12", null, TimeSpanStyles.AssumeNegative);
1028
1029                 // Fractions of seconds - f
1030                 ParseExactHelper ("3", new string [] { "%f" }, false, false, "00:00:00.3000000");
1031                 ParseExactHelper ("0", new string [] { "%f" }, false, false, "00:00:00");
1032                 ParseExactHelper ("03", new string [] { "%f" }, true, false, "dontcare"); // This would work for other elements
1033                 ParseExactHelper ("10", new string [] { "%f" }, true, false, "dontcare"); // Only a digit is accepted with '%f'
1034                 ParseExactHelper ("3", new string [] { "%ff" }, true, false, "dontcare");
1035                 ParseExactHelper ("12", new string [] { "%ff" }, false, false, "00:00:00.1200000");
1036                 ParseExactHelper ("123", new string [] { "%ff" }, true, false, "dontcare");
1037                 ParseExactHelper ("123", new string [] { "%fff" }, false, false, "00:00:00.1230000");
1038                 ParseExactHelper ("1234", new string [] { "%ffff" }, false, false, "00:00:00.1234000");
1039                 ParseExactHelper ("1234567", new string [] { "%fffffff" }, false, false, "00:00:00.1234567");
1040                 ParseExactHelper ("1234567", new string [] { "%FfFFFFF" }, true, false, "dontcare"); // Mixed f and M
1041                 ParseExactHelper ("12345678", new string [] { "%ffffffff" }, true, false, "dontcare");
1042                 ParseExactHelper ("0000000", new string [] { "%fffffff" }, false, false, "00:00:00");
1043
1044                 // Fractions of second - F
1045                 ParseExactHelper ("3", new string [] { "%F" }, false, false, "00:00:00.3000000");
1046                 ParseExactHelper ("333", new string [] { "%FFFFF" }, false, false, "00:00:00.3330000");
1047                 ParseExactHelper ("1234567", new string [] { "%FFFFFFF" }, false, false, "00:00:00.1234567");
1048
1049                 // Multiple symbols
1050                 ParseExactHelper ("9:10", new string [] { @"h\:m" }, false, false, "09:10:00");
1051                 ParseExactHelper ("9;10", new string [] { @"h\;m" }, false, false, "09:10:00");
1052                 ParseExactHelper ("10:9", new string [] { @"m\:h" }, false, false, "09:10:00");
1053                 ParseExactHelper ("10:9", new string [] { @"%m\:%h" }, false, false, "09:10:00");
1054                 ParseExactHelper ("9 10", new string [] { @"h\ m" }, false, false, "09:10:00");
1055                 ParseExactHelper ("9   10", new string [] { @"h\ \ \ m" }, false, false, "09:10:00");
1056                 ParseExactHelper (" 9:10 ", new string [] { @"h\:m" }, true, false, "dontcare");
1057                 ParseExactHelper ("9:10:11", new string [] { @"h\:m\:s" }, false, false, "09:10:11");
1058                 ParseExactHelper ("9:10:11:6", new string [] { @"h\:m\:s\:f" }, false, false, "09:10:11.6000000");
1059                 ParseExactHelper ("9:10:11:666", new string [] { @"h\:m\:s\:f" }, true, false, "dontcare"); // fff with 1 digit
1060                 ParseExactHelper ("9:10:11:", new string [] { @"h\:m\:s\:F" }, false, false, "09:10:11"); // optional frac of seconds
1061                 ParseExactHelper ("9:10:11:", new string [] { @"h\:m\:s\:FF" }, false, false, "09:10:11");
1062                 ParseExactHelper ("9:10:11::", new string [] { @"h\:m\:s\:F\:" }, false, false, "09:10:11");
1063                 ParseExactHelper ("8:9:10:11:6666666", new string [] { @"d\:h\:m\:s\:fffffff" }, false, false, "8.09:10:11.6666666");
1064                 ParseExactHelper ("8:9:10:11:6666666", new string [] { @"d\:h\:m\:s\:fffffff" }, false, false, "-8.09:10:11.6666666", 
1065                                 null, TimeSpanStyles.AssumeNegative);
1066                 ParseExactHelper ("9:10", new string [] { @"h\:h" }, true, false, "dontcare"); // Repeated element
1067
1068                 // Misc
1069                 ParseExactHelper (" 0 ", new string [] { "%d" }, true, false, "dontcare");
1070                 ParseExactHelper (" 0 ", new string [] { " %d " }, true, false, "dontcare");
1071                 ParseExactHelper ("0", new string [] { " %d " }, true, false, "dontcare");
1072                 ParseExactHelper ("::", new string [] { @"\:\:" }, false, false, "00:00:00"); // funny
1073                 ParseExactHelper ("::", new string [] { @"\:\:" }, false, false, "00:00:00", null, TimeSpanStyles.AssumeNegative);
1074                 ParseExactHelper (" 0", new string [] { @"\ d" }, false, false, "00:00:00");
1075                 ParseExactHelper ("Interval = 12:13:14", new string [] { @"'Interval = 'h\:m\:s" }, false, false, "12:13:14");
1076         }
1077
1078         void ParseExactHelper (string input, string [] formats, bool format_error, bool overflow_error, string expected, 
1079         IFormatProvider formatProvider = null, TimeSpanStyles timeSpanStyles = TimeSpanStyles.None)
1080         {
1081                 bool overflow_exc = false;
1082                 bool format_exc = false;
1083                 TimeSpan result = TimeSpan.Zero;
1084
1085                 try {
1086                         result = TimeSpan.ParseExact (input, formats, formatProvider, timeSpanStyles);
1087                 } catch (OverflowException) {
1088                         overflow_exc = true;
1089                 } catch (FormatException) {
1090                         format_exc = true;
1091                 }
1092
1093                 Assert.AreEqual (format_error, format_exc, "A1");
1094                 Assert.AreEqual (overflow_error, overflow_exc, "A2");
1095                 if (!overflow_exc && !format_exc)
1096                         Assert.AreEqual (expected, result.ToString ());
1097         }
1098
1099         // 'Ported' the ParseExact test to use TryParseExact instead.
1100         [Test]
1101         public void TryParseExact ()
1102         {
1103                 CultureInfo french_culture = CultureInfo.GetCultureInfo ("fr-FR");
1104                 CultureInfo us_culture = CultureInfo.GetCultureInfo ("en-US");
1105
1106                 //
1107                 // 'g' format - this is the short and culture sensitive format
1108                 //
1109                 string [] g_format = new string [] { "g" };
1110                 TryParseExactHelper ("12", g_format, false, "12.00:00:00");
1111                 TryParseExactHelper ("11:12", g_format, false, "11:12:00");
1112                 TryParseExactHelper ("-11:12", g_format, false, "-11:12:00");
1113                 TryParseExactHelper ("25:13", g_format, true, "dontcare");
1114                 TryParseExactHelper ("11:66", g_format, true, "dontcare"); // I'd have expected OverflowExc here
1115                 TryParseExactHelper ("11:12:13", g_format, false, "11:12:13");
1116                 TryParseExactHelper ("-11:12:13", g_format, false, "-11:12:13");
1117                 TryParseExactHelper ("10.11:12:13", g_format, true, "dontcare"); // this should work as well
1118                 TryParseExactHelper ("10.11:12:13", g_format, true, "dontcare", us_culture);
1119                 TryParseExactHelper ("10.11:12:13", g_format, true, "dontcare", CultureInfo.InvariantCulture);
1120                 TryParseExactHelper ("10:11:12:66", g_format, true, "dontcare");
1121                 TryParseExactHelper ("10:11:12:13", g_format, false, "10.11:12:13");
1122                 TryParseExactHelper ("11:12:13.6", g_format, false, "11:12:13.6000000", CultureInfo.InvariantCulture);
1123                 TryParseExactHelper ("11:12:13,6", g_format, false, "11:12:13.6000000", french_culture);
1124                 TryParseExactHelper ("10:11:12:13.6", g_format, false, "10.11:12:13.6000000", us_culture);
1125                 TryParseExactHelper (" 10:11:12:13.6 ", g_format, false, "10.11:12:13.6000000", us_culture);
1126                 TryParseExactHelper ("10:11", g_format, false, "10:11:00", null, TimeSpanStyles.None);
1127                 TryParseExactHelper ("10:11", g_format, false, "10:11:00", null, TimeSpanStyles.AssumeNegative); // no effect
1128
1129                 // 
1130                 // G format
1131                 //
1132                 string [] G_format = new string [] { "G" };
1133                 TryParseExactHelper ("9:10:12", G_format, true, "dontcare");
1134                 TryParseExactHelper ("9:10:12.6", G_format, true, "dontcare");
1135                 TryParseExactHelper ("3.9:10:12", G_format, true, "dontcare");
1136                 TryParseExactHelper ("3.9:10:12.153", G_format, true, "dontcare"); // this should be valid...
1137                 TryParseExactHelper ("3:9:10:12.153", G_format, false, "3.09:10:12.1530000", us_culture);
1138                 TryParseExactHelper ("0:9:10:12.153", G_format, false, "09:10:12.1530000", us_culture);
1139                 TryParseExactHelper ("03:09:10:12.153", G_format, false, "3.09:10:12.1530000", us_culture);
1140                 TryParseExactHelper ("003:009:0010:0012.00153", G_format, false, "3.09:10:12.0015300", us_culture);
1141                 TryParseExactHelper ("3:9:10:66.153", G_format, true, "dontcare"); // seconds out of range
1142                 TryParseExactHelper ("3:9:10:12.153", G_format, true, "dontcare", french_culture); // fr-FR uses ',' as decimal separator
1143                 TryParseExactHelper ("3:9:10:12,153", G_format, false, "3.09:10:12.1530000", french_culture);
1144                 TryParseExactHelper ("  3:9:10:12.153  ", G_format, false, "3.09:10:12.1530000", us_culture);
1145                 TryParseExactHelper ("3:9:10:13.153", G_format, false, "3.09:10:13.1530000", us_culture, TimeSpanStyles.AssumeNegative);
1146
1147                 // c format
1148                 string [] c_format = new string [] { "c" };
1149                 TryParseExactHelper ("12", c_format, false, "12.00:00:00");
1150                 TryParseExactHelper ("12:11", c_format, false, "12:11:00");
1151                 TryParseExactHelper ("12:66", c_format, true, "dontcare");
1152                 TryParseExactHelper ("10.11:12", c_format, false, "10.11:12:00");
1153                 TryParseExactHelper ("10.11:12:13", c_format, false, "10.11:12:13");
1154                 TryParseExactHelper ("10:11:12:13", c_format, true, "dontcare"); // this is normally accepted in the Parse method
1155                 TryParseExactHelper ("10.11:12:13.6", c_format, false, "10.11:12:13.6000000");
1156                 TryParseExactHelper ("10:11:12,6", c_format, true, "dontcare");
1157                 TryParseExactHelper ("10:11:12,6", c_format, true, "dontcare", french_culture);
1158                 TryParseExactHelper ("  10:11:12.6  ", c_format, false, "10:11:12.6000000");
1159                 TryParseExactHelper ("10:12", c_format, false, "10:12:00", null, TimeSpanStyles.AssumeNegative);
1160                 TryParseExactHelper ("10:123456789999", c_format, true, "dontcare");
1161
1162                 TryParseExactHelper ("10:12", new string [0], true, "dontcare");
1163                 TryParseExactHelper ("10:12", new string [] { String.Empty }, true, "dontcare");
1164                 TryParseExactHelper ("10:12", new string [] { null }, true, "dontcare");
1165
1166                 TryParseExactHelper (null, new string [] { null }, true, "dontcare");
1167         }
1168
1169         void TryParseExactHelper (string input, string [] formats, bool error, string expected, IFormatProvider formatProvider = null,
1170                         TimeSpanStyles styles = TimeSpanStyles.None)
1171         {
1172                 TimeSpan result;
1173                 bool success;
1174
1175                 success = TimeSpan.TryParseExact (input, formats, formatProvider, styles, out result);
1176                 Assert.AreEqual (!error, success);
1177                 if (!error)
1178                         Assert.AreEqual (expected, result.ToString ());
1179         }
1180
1181         [Test]
1182         public void ParseExactExceptions ()
1183         {
1184                 try {
1185                         TimeSpan.ParseExact (null, "g", null);
1186                         Assert.Fail ("#A1");
1187                 } catch (ArgumentNullException) {
1188                 }
1189
1190                 try {
1191                         TimeSpan.ParseExact ("10:12", (string)null, null);
1192                         Assert.Fail ("#A2");
1193                 } catch (ArgumentNullException) {
1194                 }
1195
1196                 try {
1197                         TimeSpan.ParseExact ("10:12", (string [])null, null);
1198                         Assert.Fail ("#A3");
1199                 } catch (ArgumentNullException) {
1200                 }
1201         }
1202
1203         [Test]
1204         public void ToStringOverloads ()
1205         {
1206                 TimeSpan ts = new TimeSpan (1, 2, 3, 4, 6);
1207
1208                 // Simple version - culture invariant
1209                 Assert.AreEqual ("1.02:03:04.0060000", ts.ToString (), "#A1");
1210                 Assert.AreEqual ("1.02:03:04.0060000", ts.ToString ("c"), "#A2");
1211                 Assert.AreEqual ("1.02:03:04.0060000", ts.ToString (null), "#A3");
1212                 Assert.AreEqual ("1.02:03:04.0060000", ts.ToString (String.Empty), "#A4");
1213
1214                 //
1215                 // IFormatProvider ones - use a culture changing numeric format.
1216                 // Also, we use fr-FR as culture, since it uses some elements different to invariant culture
1217                 //
1218                 CultureInfo culture = CultureInfo.GetCultureInfo ("fr-FR");
1219
1220                 Assert.AreEqual ("1:2:03:04,006", ts.ToString ("g", culture), "#B1");
1221                 Assert.AreEqual ("1:02:03:04,0060000", ts.ToString ("G", culture), "#B2");
1222                 Assert.AreEqual ("1.02:03:04.0060000", ts.ToString ("c", culture), "#B3"); // 'c' format ignores CultureInfo
1223                 Assert.AreEqual ("1.02:03:04.0060000", ts.ToString ("t", culture), "#B4"); // 't' and 'T' are the same as 'c'
1224                 Assert.AreEqual("1.02:03:04.0060000", ts.ToString("T", culture), "#B5");
1225
1226                 ts = new TimeSpan (4, 5, 6);
1227                 Assert.AreEqual ("4:05:06", ts.ToString ("g", culture), "#C1");
1228                 Assert.AreEqual ("0:04:05:06,0000000", ts.ToString ("G", culture), "#C2");
1229         }
1230
1231         [Test]
1232         public void ToStringCustomFormats ()
1233         {
1234                 TimeSpan ts = new TimeSpan (1, 3, 5, 7);
1235
1236                 Assert.AreEqual ("1", ts.ToString ("%d"), "#A0");
1237                 Assert.AreEqual ("3", ts.ToString ("%h"), "#A1");
1238                 Assert.AreEqual ("5", ts.ToString ("%m"), "#A2");
1239                 Assert.AreEqual ("7", ts.ToString ("%s"), "#A3");
1240                 Assert.AreEqual ("0", ts.ToString ("%f"), "#A4");
1241                 Assert.AreEqual (String.Empty, ts.ToString ("%F"), "#A5"); // Nothing to display
1242
1243                 Assert.AreEqual ("01", ts.ToString ("dd"), "#B0");
1244                 Assert.AreEqual ("00000001", ts.ToString ("dddddddd"), "#B1");
1245                 Assert.AreEqual ("03", ts.ToString ("hh"), "#B2");
1246                 Assert.AreEqual ("05", ts.ToString ("mm"), "#B3");
1247                 Assert.AreEqual ("07", ts.ToString ("ss"), "#B4");
1248                 Assert.AreEqual ("00", ts.ToString ("ff"), "#B5");
1249                 Assert.AreEqual ("0000000", ts.ToString ("fffffff"), "#B6");
1250                 Assert.AreEqual (String.Empty, ts.ToString ("FF"), "#B7");
1251
1252                 Assert.AreEqual ("01;03;05", ts.ToString (@"dd\;hh\;mm"), "#C0");
1253                 Assert.AreEqual ("05 07", ts.ToString (@"mm\ ss"), "#C1");
1254                 Assert.AreEqual ("05 07 ", ts.ToString (@"mm\ ss\ FF"), "#C2");
1255                 Assert.AreEqual ("Result = 3 hours with 5 minutes and 7 seconds",
1256                                 ts.ToString (@"'Result = 'h' hours with 'm' minutes and 's' seconds'"), "#C3");
1257                 Assert.AreEqual ("  ", ts.ToString (@"\ \ "), "#C4");
1258
1259                 ts = new TimeSpan (1, 3, 5, 7, 153);
1260                 Assert.AreEqual ("1", ts.ToString ("%F"), "#D0");
1261                 Assert.AreEqual ("15", ts.ToString ("FF"), "#D1"); // Don't use %, as the parser gets confused here
1262                 Assert.AreEqual ("153", ts.ToString ("FFFFFFF"), "#D2");
1263
1264                 // Negative values are shown without sign
1265                 ts = new TimeSpan (-1, -3, -5);
1266                 Assert.AreEqual ("1", ts.ToString ("%h"), "#E0");
1267                 Assert.AreEqual ("3", ts.ToString ("%m"), "#E1");
1268                 Assert.AreEqual ("5", ts.ToString ("%s"), "#E2");
1269
1270                 ts = new TimeSpan (123456789);
1271                 Assert.AreEqual ("12.3", ts.ToString ("s\\.f"), "#F0");
1272                 Assert.AreEqual ("12.3", ts.ToString ("s\\.F"), "#F1");
1273                 Assert.AreEqual ("12.3456789", ts.ToString ("s\\.fffffff"), "#F2");
1274                 Assert.AreEqual ("12.345678", ts.ToString ("s\\.ffffff"), "#F3");
1275
1276                 ts = new TimeSpan (1234);
1277                 Assert.AreEqual ("0.000123", ts.ToString ("s\\.ffffff"), "#G0");
1278                 Assert.AreEqual ("0.0001", ts.ToString ("s\\.ffff"), "#G1");
1279                 Assert.AreEqual ("0.", ts.ToString ("s\\.F"), "#G2");
1280                 Assert.AreEqual ("0.", ts.ToString ("s\\.FFF"), "#G3");
1281
1282                 ts = TimeSpan.FromSeconds (0.05);
1283                 Assert.AreEqual (".0", ts.ToString ("\\.f"), "#H0");
1284                 Assert.AreEqual (".", ts.ToString ("\\.F"), "#H1");
1285         }
1286
1287         [Test]
1288         public void ToStringOverloadsErrors ()
1289         {
1290                 TimeSpan ts = new TimeSpan (10, 10, 10);
1291                 string result;
1292
1293                 try {
1294                         result = ts.ToString ("non-valid");
1295                         Assert.Fail ("#1");
1296                 } catch (FormatException) {
1297                 }
1298
1299                 try {
1300                         result = ts.ToString ("C");
1301                         Assert.Fail ("#2");
1302                 } catch (FormatException) {
1303                 }
1304
1305                 try
1306                 {
1307                         ts.ToString ("m");
1308                         Assert.Fail ("#3");
1309                 } catch (FormatException) {
1310                 }
1311
1312                 try
1313                 {
1314                         ts.ToString ("d"); // Missing % for single char
1315                         Assert.Fail ("#4");
1316                 } catch (FormatException)
1317                 {
1318                 }
1319
1320                 try
1321                 {
1322                         ts.ToString ("ddddddddd");
1323                         Assert.Fail ("#5");
1324                 } catch (FormatException)
1325                 {
1326                 }
1327
1328                 try
1329                 {
1330                         ts.ToString ("hhh");
1331                         Assert.Fail ("#5");
1332                 } catch (FormatException)
1333                 {
1334                 }
1335
1336                 try
1337                 {
1338                         ts.ToString ("ffffffff");
1339                         Assert.Fail ("6");
1340                 } catch (FormatException)
1341                 {
1342                 }
1343         }
1344 #endif
1345 }
1346
1347 }