[bcl] Remove NET_4_0 defines from class libs
[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                 // In 4.0 when the first part is out of range, it parses it as day.
642                 ParseHelper (" 25:11:12 ", false, false, "25.11:12:00");
643                 ParseHelper (" 24:11:12 ", false, false, "24.11:12:00");
644                 ParseHelper (" 23:11:12 ", false, false, "23:11:12");
645
646                 ParseHelper ("-21.23:59:59.9999999", false, false, "-21.23:59:59.9999999");
647                 ParseHelper ("10:12  ", false, false, "10:12:00");
648                 ParseHelper ("aaa", true, false, "dontcare");
649
650                 ParseHelper ("100000000000000.1:1:1", false, true, "dontcare");
651                 ParseHelper ("24:60:60", false, true, "dontcare");
652                 ParseHelper ("0001:0002:0003.12     ", false, false, "01:02:03.1200000");
653
654                 // In 4.0 when a section has more than 7 digits an OverflowException is thrown.
655                 ParseHelper (" 1:2:3:12345678 ", false, true, "dontcare");
656
657                 ParseHelper ("10:11:12:13", false, false, "10.11:12:13"); // Days using : instead of . as separator
658                 ParseHelper ("10.11", true, false, "dontcare"); // days+hours is invalid
659
660                 // Force the use of french culture -which is using a non common NumberDecimalSeparator-
661                 // as current culture, to show that the Parse method is *actually* being culture sensitive
662                 // *and* also keeping the compatibility with '.'
663                 CultureInfo french_culture = CultureInfo.GetCultureInfo ("fr-FR");
664                 CultureInfo prev_culture = CultureInfo.CurrentCulture;
665                 try {
666                         Thread.CurrentThread.CurrentCulture = french_culture;
667                         ParseHelper ("10:10:10,006", false, false, "10:10:10.0060000");
668                         ParseHelper ("10:10:10.006", false, false, "10:10:10.0060000");
669                 } finally {
670                         // restore culture
671                         Thread.CurrentThread.CurrentCulture = prev_culture;
672                 }
673
674                 ParseHelper ("00:00:00", false, false, "00:00:00");
675                 ParseHelper ("00:10:00", false, false, "00:10:00");
676         }
677
678         // LAMESPEC: timespan in documentation is wrong - hh:mm:ss isn't mandatory
679         [Test]
680         public void Parse_Days_WithoutColon () 
681         {
682                 TimeSpan ts = TimeSpan.Parse ("1");
683                 Assert.AreEqual (1, ts.Days, "Days");
684         }
685
686         [Test]
687         public void TestSubstract ()
688         {
689                 TimeSpan t1 = new TimeSpan (2,3,4,5,6);
690                 TimeSpan t2 = new TimeSpan (1,2,3,4,5);
691                 TimeSpan t3 = t1 - t2;
692                 TimeSpan t4 = t1.Subtract (t2);
693                 TimeSpan t5;
694                 bool exception;
695
696                 Assert.AreEqual ("1.01:01:01.0010000", t3.ToString (), "A1");
697                 Assert.AreEqual ("1.01:01:01.0010000", t4.ToString (), "A2");
698                 try {
699                         t5 = TimeSpan.MinValue - new TimeSpan (1);
700                         exception = false;
701                 }
702                 catch (OverflowException) {
703                         exception = true;
704                 }
705                 Assert.IsTrue (exception, "A3");
706         }
707
708         [Test]
709         public void TestToString () 
710         {
711                 TimeSpan t1 = new TimeSpan (1,2,3,4,5);
712                 TimeSpan t2 = -t1;
713                 
714                 Assert.AreEqual ("1.02:03:04.0050000", t1.ToString (), "A1");
715                 Assert.AreEqual ("-1.02:03:04.0050000", t2.ToString (), "A2");
716                 Assert.AreEqual ("10675199.02:48:05.4775807", TimeSpan.MaxValue.ToString (), "A3");
717                 Assert.AreEqual ("-10675199.02:48:05.4775808", TimeSpan.MinValue.ToString (), "A4");
718         }
719
720         [Test]
721         public void ToString_Constants () 
722         {
723                 Assert.AreEqual ("00:00:00", TimeSpan.Zero.ToString (), "Zero");
724                 Assert.AreEqual ("10675199.02:48:05.4775807", TimeSpan.MaxValue.ToString (), "MaxValue");
725                 Assert.AreEqual ("-10675199.02:48:05.4775808", TimeSpan.MinValue.ToString (), "MinValue");
726         }
727
728         [Test]
729         public void Parse_InvalidValuesAndFormat_ExceptionOrder () 
730         {
731                 // hours should be between 0 and 23 but format is also invalid (too many dots)
732                 // In 2.0 overflow as precedence over format, but not in 4.0
733                 try {
734                         TimeSpan.Parse ("0.99.99.0");
735                         Assert.Fail ("#A1");
736                 } catch (FormatException) {
737                 }
738                 try {
739                         TimeSpan.Parse ("0.999999999999.99.0");
740                         Assert.Fail ("#A2");
741                 } catch (OverflowException) {
742                 }
743         }
744
745         [Test]
746         public void Parse_MinMaxValues () 
747         {
748                 Assert.AreEqual (TimeSpan.MaxValue, TimeSpan.Parse ("10675199.02:48:05.4775807"), "MaxValue");
749                 Assert.AreEqual (TimeSpan.MinValue, TimeSpan.Parse ("-10675199.02:48:05.4775808"), "MinValue");
750         }
751
752         [Test]
753         [ExpectedException (typeof (OverflowException))]
754         public void Parse_OverMaxValue() 
755         {
756                 TimeSpan.Parse ("10675199.02:48:05.4775808");
757         }
758
759         [Test]
760         [ExpectedException (typeof (OverflowException))]
761         public void Parse_UnderMinValue() 
762         {
763                 TimeSpan.Parse ("-10675199.02:48:05.4775809");
764         }
765
766         [Test]
767         public void ParseMissingSeconds ()
768         {
769                 // as seen in ML for http://resources.esri.com/arcgisserver/apis/silverlight/
770                 TimeSpan ts = TimeSpan.Parse ("0:0:.75");
771
772                 Assert.AreEqual (0, ts.Days, "Days");
773                 Assert.AreEqual (0, ts.Hours, "Hours");
774                 Assert.AreEqual (750, ts.Milliseconds, "Milliseconds");
775                 Assert.AreEqual (0, ts.Minutes, "Minutes");
776                 Assert.AreEqual (0, ts.Seconds, "Seconds");
777                 Assert.AreEqual (7500000, ts.Ticks, "Ticks");
778                 Assert.AreEqual (0.0000086805555555555555, ts.TotalDays, 0.00000000000000001, "TotalDays");
779                 Assert.AreEqual (0.00020833333333333332, ts.TotalHours, 0.00000000000000001, "TotalHours");
780                 Assert.AreEqual (750.0, ts.TotalMilliseconds, "TotalMilliseconds");
781                 Assert.AreEqual (0.0125, ts.TotalMinutes, "TotalMinutes");
782                 Assert.AreEqual (0.75, ts.TotalSeconds, "TotalSeconds");
783         }
784
785         // 'Ported' the Parse test to use TryParse
786         [Test]
787         public void TryParse ()
788         {
789                 TimeSpan result;
790
791                 Assert.AreEqual (true, TimeSpan.TryParse (" 13:45:15 ", out result), "#A1");
792                 Assert.AreEqual ("13:45:15", result.ToString (), "#A2");
793
794                 Assert.AreEqual (true, TimeSpan.TryParse (" -1:2:3 ", out result), "#B1");
795                 Assert.AreEqual ("-01:02:03", result.ToString (), "#B2");
796
797                 Assert.AreEqual (false, TimeSpan.TryParse ("aaa", out result), "#C2");
798
799                 Assert.AreEqual (true, TimeSpan.TryParse ("-21.23:59:59.9999999", out result), "#D1");
800                 Assert.AreEqual ("-21.23:59:59.9999999", result.ToString (), "#D2");
801
802                 Assert.AreEqual (false, TimeSpan.TryParse ("100000000000000.1:1:1", out result), "#E1");
803                 Assert.AreEqual (false, TimeSpan.TryParse ("24:60:60", out result), "#E2");
804
805                 Assert.AreEqual (true, TimeSpan.TryParse ("0001:0002:0003.12     ", out result), "#F1");
806
807                 Assert.AreEqual (false, TimeSpan.TryParse (" 1:2:3:12345678 ", out result), "#G1");
808
809                 // Min and Max values
810                 Assert.AreEqual (true, TimeSpan.TryParse ("10675199.02:48:05.4775807", out result), "MaxValue#1");
811                 Assert.AreEqual (TimeSpan.MaxValue, result, "MaxValue#2");
812                 Assert.AreEqual (true, TimeSpan.TryParse ("-10675199.02:48:05.4775808", out result), "MinValue#1");
813                 Assert.AreEqual (TimeSpan.MinValue, result, "MinValue#2");
814
815                 // Force the use of french culture -which is using a non common NumberDecimalSeparator-
816                 // as current culture, to show that the Parse method is *actually* being culture sensitive
817                 CultureInfo french_culture = CultureInfo.GetCultureInfo ("fr-FR");
818                 CultureInfo prev_culture = CultureInfo.CurrentCulture;
819                 result = new TimeSpan (0, 10, 10, 10, 6);
820                 try {
821                         Thread.CurrentThread.CurrentCulture = french_culture;
822                         Assert.AreEqual (true, TimeSpan.TryParse ("10:10:10,006", out result), "#CultureSensitive1");
823                         Assert.AreEqual ("10:10:10.0060000", result.ToString (), "#CultureSensitive2");
824                 } finally {
825                         // restore culture
826                         Thread.CurrentThread.CurrentCulture = prev_culture;
827                 }
828         }
829
830         [Test]
831         public void TryParseErrors ()
832         {
833                 TimeSpan result;
834
835                 Assert.AreEqual (false, TimeSpan.TryParse ("0.99.99.0", out result), "Format#1");
836                 Assert.AreEqual (false, TimeSpan.TryParse ("10675199.02:48:05.4775808", out result), "OverMaxValue");
837                 Assert.AreEqual (false, TimeSpan.TryParse ("-10675199.02:48:05.4775809", out result), "UnderMinValue");
838         }
839
840         [Test]
841         public void TryParseOverloads ()
842         { 
843                 TimeSpan result;
844
845                 // We use fr-FR culture since its NumericDecimalSeparator is not the same used by
846                 // most cultures - including the invariant one.
847                 CultureInfo french_culture = CultureInfo.GetCultureInfo ("fr-FR");
848                 Assert.AreEqual (true, TimeSpan.TryParse ("11:50:50,006", french_culture, out result), "#A1");
849
850                 // LAMESPEC - msdn states that an instance of DateTimeFormatInfo is retrieved to
851                 // obtain culture sensitive information, but at least in the betas that's false
852                 DateTimeFormatInfo format_info = new DateTimeFormatInfo ();
853                 format_info.TimeSeparator = ";";
854                 Assert.AreEqual (false, TimeSpan.TryParse ("11;50;50", format_info, out result), "#B1");
855                 Assert.AreEqual (true, TimeSpan.TryParse ("11:50:50", format_info, out result), "#B2");
856         }
857
858         [Test]
859         public void ParseExact ()
860         {
861                 CultureInfo french_culture = CultureInfo.GetCultureInfo ("fr-FR");
862                 CultureInfo us_culture = CultureInfo.GetCultureInfo ("en-US");
863
864                 // At this point we are only missing the style bites and then we are
865                 // pretty much done with the standard formats.
866
867                 //
868                 // 'g' format - this is the short and culture sensitive format
869                 //
870                 string [] g_format = new string [] { "g" };
871                 ParseExactHelper ("12", g_format, false, false, "12.00:00:00");
872                 ParseExactHelper ("11:12", g_format, false, false, "11:12:00");
873                 ParseExactHelper ("-11:12", g_format, false, false, "-11:12:00");
874                 ParseExactHelper ("25:13", g_format, true, false, "dontcare");
875                 ParseExactHelper ("11:66", g_format, true, false, "dontcare"); // I'd have expected OverflowExc here
876                 ParseExactHelper ("11:12:13", g_format, false, false, "11:12:13");
877                 ParseExactHelper ("-11:12:13", g_format, false, false, "-11:12:13");
878                 ParseExactHelper ("10.11:12:13", g_format, true, false, "dontcare"); // this should work as well
879                 ParseExactHelper ("10.11:12:13", g_format, true, false, "dontcare", us_culture);
880                 ParseExactHelper ("10.11:12:13", g_format, true, false, "dontcare", CultureInfo.InvariantCulture);
881                 ParseExactHelper ("10:11:12:66", g_format, true, false, "dontcare");
882                 ParseExactHelper ("10:11:12:13", g_format, false, false, "10.11:12:13");
883                 ParseExactHelper ("11:12:13.6", g_format, false, false, "11:12:13.6000000", CultureInfo.InvariantCulture);
884                 ParseExactHelper ("11:12:13,6", g_format, false, false, "11:12:13.6000000", french_culture);
885                 ParseExactHelper ("10:11:12:13.6", g_format, false, false, "10.11:12:13.6000000", us_culture);
886                 ParseExactHelper (" 10:11:12:13.6 ", g_format, false, false, "10.11:12:13.6000000", us_culture);
887                 ParseExactHelper ("10:11", g_format, false, false, "10:11:00", null, TimeSpanStyles.None);
888                 ParseExactHelper ("10:11", g_format, false, false, "10:11:00", null, TimeSpanStyles.AssumeNegative); // no effect
889
890                 // 
891                 // G format
892                 //
893                 string [] G_format = new string [] { "G" };
894                 ParseExactHelper ("9:10:12", G_format, true, false, "dontcare");
895                 ParseExactHelper ("9:10:12.6", G_format, true, false, "dontcare");
896                 ParseExactHelper ("3.9:10:12", G_format, true, false, "dontcare");
897                 ParseExactHelper ("3.9:10:12.153", G_format, true, false, "dontcare"); // this should be valid...
898                 ParseExactHelper ("3:9:10:12.153", G_format, false, false, "3.09:10:12.1530000", us_culture);
899                 ParseExactHelper ("0:9:10:12.153", G_format, false, false, "09:10:12.1530000", us_culture);
900                 ParseExactHelper ("03:09:10:12.153", G_format, false, false, "3.09:10:12.1530000", us_culture);
901                 ParseExactHelper ("003:009:0010:0012.00153", G_format, false, false, "3.09:10:12.0015300", us_culture);
902                 ParseExactHelper ("3:9:10:66.153", G_format, true, false, "dontcare"); // seconds out of range
903                 ParseExactHelper ("3:9:10:12.153", G_format, true, false, "dontcare", french_culture); // fr-FR uses ',' as decimal separator
904                 ParseExactHelper ("3:9:10:12,153", G_format, false, false, "3.09:10:12.1530000", french_culture);
905                 ParseExactHelper ("  3:9:10:12.153  ", G_format, false, false, "3.09:10:12.1530000", us_culture);
906                 ParseExactHelper ("3:9:10:13.153", G_format, false, false, "3.09:10:13.1530000", us_culture, TimeSpanStyles.AssumeNegative);
907
908                 // c format
909                 string [] c_format = new string [] { "c" };
910                 ParseExactHelper ("12", c_format, false, false, "12.00:00:00");
911                 ParseExactHelper ("12:11", c_format, false, false, "12:11:00");
912                 ParseExactHelper ("12:66", c_format, true, false, "dontcare");
913                 ParseExactHelper ("10.11:12", c_format, false, false, "10.11:12:00");
914                 ParseExactHelper ("10.11:12:13", c_format, false, false, "10.11:12:13");
915                 ParseExactHelper ("10:11:12:13", c_format, true, false, "dontcare"); // this is normally accepted in the Parse method
916                 ParseExactHelper ("10.11:12:13.6", c_format, false, false, "10.11:12:13.6000000");
917                 ParseExactHelper ("10:11:12,6", c_format, true, false, "dontcare");
918                 ParseExactHelper ("10:11:12,6", c_format, true, false, "dontcare", french_culture);
919                 ParseExactHelper ("  10:11:12.6  ", c_format, false, false, "10:11:12.6000000");
920                 ParseExactHelper ("10:12", c_format, false, false, "10:12:00", null, TimeSpanStyles.AssumeNegative);
921                 ParseExactHelper ("10:123456789999", c_format, true, false, "dontcare");
922
923                 ParseExactHelper ("10:12", new string [0], true, false, "dontcare");
924                 ParseExactHelper ("10:12", new string [] { String.Empty }, true, false, "dontcare");
925                 ParseExactHelper ("10:12", new string [] { null }, true, false, "dontcare");
926         }
927
928         [Test]
929         public void ParseExactMultipleFormats ()
930         {
931                 ParseExactHelper ("10:12", new string [] { "G", "g" }, false, false, "10:12:00");
932                 ParseExactHelper ("10:12", new string [] { "g", "G" }, false, false, "10:12:00");
933                 ParseExactHelper ("7.8:9:10", new string [] { "G", "g" }, true, false, "dontcare");
934                 ParseExactHelper ("7.8:9:10", new string [] { "G", "g", "c" }, false, false, "7.08:09:10");
935                 ParseExactHelper ("7:8:9:10", new string [] { "c", "g" }, false, false, "7.08:09:10");
936                 ParseExactHelper ("7:8:9:10", new string [] { "c", "G" }, true, false, "dontcare");
937                 ParseExactHelper ("7.123456789:1", new string [] { "c", "G", "g" }, true, false, "dontcare");
938                 ParseExactHelper ("7.123456789:1", new string [] { "G", "g", "c" }, true, false, "dontcare");
939                 ParseExactHelper ("1234567890123456", new string [] { "c", "g" }, true, false, "dontcare"); // I'd expect an OverflowException
940                 ParseExactHelper ("10:12", new string [] { null, "c", "g" }, true, false, "10:12:00");
941                 ParseExactHelper ("10:12", new string [] { String.Empty, "c", "g" }, true, false, "10:12:00");
942         }
943
944         [Test]
945         public void ParseExactCustomFormats ()
946         {
947                 // Days
948                 ParseExactHelper ("33", new string [] { "%d" }, false, false, "33.00:00:00");
949                 ParseExactHelper ("00", new string [] { "%d" }, false, false, "00:00:00");
950                 ParseExactHelper ("33", new string [] { "%dd" }, false, false, "33.00:00:00");
951                 ParseExactHelper ("3333", new string [] { "%d" }, false, false, "3333.00:00:00");
952                 ParseExactHelper ("3333", new string [] { "%ddd" }, true, false, "3333.00:00:00"); // 'dd' mismatch the digit count
953                 ParseExactHelper ("3333", new string [] { "%dddd" }, false, false, "3333.00:00:00");
954                 ParseExactHelper ("00033", new string [] { "%ddddd" }, false, false, "33.00:00:00");
955                 ParseExactHelper ("00033", new string [] { "%d" }, false, false, "33.00:00:00");
956                 ParseExactHelper ("00000003", new string [] { "%dddddddd" }, false, false, "3.00:00:00"); // up to 8 'd'
957                 ParseExactHelper ("000000003", new string [] { "%ddddddddd" }, true, false, "dontcare");
958                 ParseExactHelper ("33", new string [] { "d" }, true, false, "33.00:00:00"); // This is sort of weird.
959                 ParseExactHelper ("33", new string [] { "dd" }, false, false, "33.00:00:00");
960                 ParseExactHelper ("-33", new string [] { "%d" }, true, false, "dontcare");
961                 ParseExactHelper ("33", new string [] { "%d" }, false, false, "-33.00:00:00", null, TimeSpanStyles.AssumeNegative);
962
963                 // Hours
964                 ParseExactHelper ("12", new string [] { "%h" }, false, false, "12:00:00");
965                 ParseExactHelper ("00", new string [] { "%h" }, false, false, "00:00:00");
966                 ParseExactHelper ("012", new string [] { "%h" }, true, false, "dontcare"); // more than 2 digits
967                 ParseExactHelper ("00012", new string [] { "%hhhhh" }, true, false, "dontcare");
968                 ParseExactHelper ("15", new string [] { "%h" }, false, false, "15:00:00");
969                 ParseExactHelper ("24", new string [] { "%h" }, true, false, "dontcare");
970                 ParseExactHelper ("15", new string [] { "%hh" }, false, false, "15:00:00");
971                 ParseExactHelper ("1", new string [] { "%hh" }, true, false, "dontcare"); // 'hh' but a single digit
972                 ParseExactHelper ("01", new string [] { "%hh" }, false, false, "01:00:00");
973                 ParseExactHelper ("015", new string [] { "%hhh" }, true, false, "dontcare"); // Too many 'h'
974                 ParseExactHelper ("12", new string [] { "h" }, true, false, "dontcare");
975                 ParseExactHelper ("12", new string [] { "hh" }, false, false, "12:00:00");
976                 ParseExactHelper ("-15", new string [] {"%h"}, true, false, "dontcare"); // Explicit - not accepted
977                 ParseExactHelper ("15", new string [] { "%h" }, false, false, "-15:00:00", null, TimeSpanStyles.AssumeNegative);
978                 ParseExactHelper ("15", new string [] { "%H" }, true, false, "dontcare"); // Uppercase is not accepted
979
980                 // Minutes
981                 ParseExactHelper ("12", new string [] { "%m" }, false, false, "00:12:00");
982                 ParseExactHelper ("00", new string [] { "%m" }, false, false, "00:00:00");
983                 ParseExactHelper ("60", new string [] { "%m" }, true, false, "dontcare");
984                 ParseExactHelper ("12", new string [] { "%mm" }, false, false, "00:12:00");
985                 ParseExactHelper ("1", new string [] { "%mm" }, true, false, "dontcare");
986                 ParseExactHelper ("12", new string [] { "%mmm" }, true, false, "dontcare");
987                 ParseExactHelper ("12", new string [] { "m" }, true, false, "dontcare");
988                 ParseExactHelper ("12", new string [] { "mm" }, false, false, "00:12:00");
989                 ParseExactHelper ("-12", new string [] { "%m" }, true, false, "dontcare");
990                 ParseExactHelper ("12", new string [] { "%m" }, false, false, "-00:12:00", null, TimeSpanStyles.AssumeNegative);
991                 ParseExactHelper ("12", new string [] { "%M" }, true, false, "dontcare");
992
993                 // Seconds
994                 ParseExactHelper ("12", new string [] { "%s" }, false, false, "00:00:12");
995                 ParseExactHelper ("00", new string [] { "%s" }, false, false, "00:00:00");
996                 ParseExactHelper ("000", new string [] { "%s" }, true, false, "dontcare");
997                 ParseExactHelper ("12", new string [] { "%ss" }, false, false, "00:00:12");
998                 ParseExactHelper ("12", new string [] { "%sss" }, true, false, "dontcare");
999                 ParseExactHelper ("60", new string [] { "%s" }, true, false, "dontcare");
1000                 ParseExactHelper ("-12", new string [] { "%s" }, true, false, "dontcare");
1001                 ParseExactHelper ("12", new string [] { "%s" }, false, false, "-00:00:12", null, TimeSpanStyles.AssumeNegative);
1002
1003                 // Fractions of seconds - f
1004                 ParseExactHelper ("3", new string [] { "%f" }, false, false, "00:00:00.3000000");
1005                 ParseExactHelper ("0", new string [] { "%f" }, false, false, "00:00:00");
1006                 ParseExactHelper ("03", new string [] { "%f" }, true, false, "dontcare"); // This would work for other elements
1007                 ParseExactHelper ("10", new string [] { "%f" }, true, false, "dontcare"); // Only a digit is accepted with '%f'
1008                 ParseExactHelper ("3", new string [] { "%ff" }, true, false, "dontcare");
1009                 ParseExactHelper ("12", new string [] { "%ff" }, false, false, "00:00:00.1200000");
1010                 ParseExactHelper ("123", new string [] { "%ff" }, true, false, "dontcare");
1011                 ParseExactHelper ("123", new string [] { "%fff" }, false, false, "00:00:00.1230000");
1012                 ParseExactHelper ("1234", new string [] { "%ffff" }, false, false, "00:00:00.1234000");
1013                 ParseExactHelper ("1234567", new string [] { "%fffffff" }, false, false, "00:00:00.1234567");
1014                 ParseExactHelper ("1234567", new string [] { "%FfFFFFF" }, true, false, "dontcare"); // Mixed f and M
1015                 ParseExactHelper ("12345678", new string [] { "%ffffffff" }, true, false, "dontcare");
1016                 ParseExactHelper ("0000000", new string [] { "%fffffff" }, false, false, "00:00:00");
1017
1018                 // Fractions of second - F
1019                 ParseExactHelper ("3", new string [] { "%F" }, false, false, "00:00:00.3000000");
1020                 ParseExactHelper ("333", new string [] { "%FFFFF" }, false, false, "00:00:00.3330000");
1021                 ParseExactHelper ("1234567", new string [] { "%FFFFFFF" }, false, false, "00:00:00.1234567");
1022
1023                 // Multiple symbols
1024                 ParseExactHelper ("9:10", new string [] { @"h\:m" }, false, false, "09:10:00");
1025                 ParseExactHelper ("9;10", new string [] { @"h\;m" }, false, false, "09:10:00");
1026                 ParseExactHelper ("10:9", new string [] { @"m\:h" }, false, false, "09:10:00");
1027                 ParseExactHelper ("10:9", new string [] { @"%m\:%h" }, false, false, "09:10:00");
1028                 ParseExactHelper ("9 10", new string [] { @"h\ m" }, false, false, "09:10:00");
1029                 ParseExactHelper ("9   10", new string [] { @"h\ \ \ m" }, false, false, "09:10:00");
1030                 ParseExactHelper (" 9:10 ", new string [] { @"h\:m" }, true, false, "dontcare");
1031                 ParseExactHelper ("9:10:11", new string [] { @"h\:m\:s" }, false, false, "09:10:11");
1032                 ParseExactHelper ("9:10:11:6", new string [] { @"h\:m\:s\:f" }, false, false, "09:10:11.6000000");
1033                 ParseExactHelper ("9:10:11:666", new string [] { @"h\:m\:s\:f" }, true, false, "dontcare"); // fff with 1 digit
1034                 ParseExactHelper ("9:10:11:", new string [] { @"h\:m\:s\:F" }, false, false, "09:10:11"); // optional frac of seconds
1035                 ParseExactHelper ("9:10:11:", new string [] { @"h\:m\:s\:FF" }, false, false, "09:10:11");
1036                 ParseExactHelper ("9:10:11::", new string [] { @"h\:m\:s\:F\:" }, false, false, "09:10:11");
1037                 ParseExactHelper ("8:9:10:11:6666666", new string [] { @"d\:h\:m\:s\:fffffff" }, false, false, "8.09:10:11.6666666");
1038                 ParseExactHelper ("8:9:10:11:6666666", new string [] { @"d\:h\:m\:s\:fffffff" }, false, false, "-8.09:10:11.6666666", 
1039                                 null, TimeSpanStyles.AssumeNegative);
1040                 ParseExactHelper ("9:10", new string [] { @"h\:h" }, true, false, "dontcare"); // Repeated element
1041
1042                 // Misc
1043                 ParseExactHelper (" 0 ", new string [] { "%d" }, true, false, "dontcare");
1044                 ParseExactHelper (" 0 ", new string [] { " %d " }, true, false, "dontcare");
1045                 ParseExactHelper ("0", new string [] { " %d " }, true, false, "dontcare");
1046                 ParseExactHelper ("::", new string [] { @"\:\:" }, false, false, "00:00:00"); // funny
1047                 ParseExactHelper ("::", new string [] { @"\:\:" }, false, false, "00:00:00", null, TimeSpanStyles.AssumeNegative);
1048                 ParseExactHelper (" 0", new string [] { @"\ d" }, false, false, "00:00:00");
1049                 ParseExactHelper ("Interval = 12:13:14", new string [] { @"'Interval = 'h\:m\:s" }, false, false, "12:13:14");
1050         }
1051
1052         void ParseExactHelper (string input, string [] formats, bool format_error, bool overflow_error, string expected, 
1053         IFormatProvider formatProvider = null, TimeSpanStyles timeSpanStyles = TimeSpanStyles.None)
1054         {
1055                 bool overflow_exc = false;
1056                 bool format_exc = false;
1057                 TimeSpan result = TimeSpan.Zero;
1058
1059                 try {
1060                         result = TimeSpan.ParseExact (input, formats, formatProvider, timeSpanStyles);
1061                 } catch (OverflowException) {
1062                         overflow_exc = true;
1063                 } catch (FormatException) {
1064                         format_exc = true;
1065                 }
1066
1067                 Assert.AreEqual (format_error, format_exc, "A1");
1068                 Assert.AreEqual (overflow_error, overflow_exc, "A2");
1069                 if (!overflow_exc && !format_exc)
1070                         Assert.AreEqual (expected, result.ToString ());
1071         }
1072
1073         // 'Ported' the ParseExact test to use TryParseExact instead.
1074         [Test]
1075         public void TryParseExact ()
1076         {
1077                 CultureInfo french_culture = CultureInfo.GetCultureInfo ("fr-FR");
1078                 CultureInfo us_culture = CultureInfo.GetCultureInfo ("en-US");
1079
1080                 //
1081                 // 'g' format - this is the short and culture sensitive format
1082                 //
1083                 string [] g_format = new string [] { "g" };
1084                 TryParseExactHelper ("12", g_format, false, "12.00:00:00");
1085                 TryParseExactHelper ("11:12", g_format, false, "11:12:00");
1086                 TryParseExactHelper ("-11:12", g_format, false, "-11:12:00");
1087                 TryParseExactHelper ("25:13", g_format, true, "dontcare");
1088                 TryParseExactHelper ("11:66", g_format, true, "dontcare"); // I'd have expected OverflowExc here
1089                 TryParseExactHelper ("11:12:13", g_format, false, "11:12:13");
1090                 TryParseExactHelper ("-11:12:13", g_format, false, "-11:12:13");
1091                 TryParseExactHelper ("10.11:12:13", g_format, true, "dontcare"); // this should work as well
1092                 TryParseExactHelper ("10.11:12:13", g_format, true, "dontcare", us_culture);
1093                 TryParseExactHelper ("10.11:12:13", g_format, true, "dontcare", CultureInfo.InvariantCulture);
1094                 TryParseExactHelper ("10:11:12:66", g_format, true, "dontcare");
1095                 TryParseExactHelper ("10:11:12:13", g_format, false, "10.11:12:13");
1096                 TryParseExactHelper ("11:12:13.6", g_format, false, "11:12:13.6000000", CultureInfo.InvariantCulture);
1097                 TryParseExactHelper ("11:12:13,6", g_format, false, "11:12:13.6000000", french_culture);
1098                 TryParseExactHelper ("10:11:12:13.6", g_format, false, "10.11:12:13.6000000", us_culture);
1099                 TryParseExactHelper (" 10:11:12:13.6 ", g_format, false, "10.11:12:13.6000000", us_culture);
1100                 TryParseExactHelper ("10:11", g_format, false, "10:11:00", null, TimeSpanStyles.None);
1101                 TryParseExactHelper ("10:11", g_format, false, "10:11:00", null, TimeSpanStyles.AssumeNegative); // no effect
1102
1103                 // 
1104                 // G format
1105                 //
1106                 string [] G_format = new string [] { "G" };
1107                 TryParseExactHelper ("9:10:12", G_format, true, "dontcare");
1108                 TryParseExactHelper ("9:10:12.6", G_format, true, "dontcare");
1109                 TryParseExactHelper ("3.9:10:12", G_format, true, "dontcare");
1110                 TryParseExactHelper ("3.9:10:12.153", G_format, true, "dontcare"); // this should be valid...
1111                 TryParseExactHelper ("3:9:10:12.153", G_format, false, "3.09:10:12.1530000", us_culture);
1112                 TryParseExactHelper ("0:9:10:12.153", G_format, false, "09:10:12.1530000", us_culture);
1113                 TryParseExactHelper ("03:09:10:12.153", G_format, false, "3.09:10:12.1530000", us_culture);
1114                 TryParseExactHelper ("003:009:0010:0012.00153", G_format, false, "3.09:10:12.0015300", us_culture);
1115                 TryParseExactHelper ("3:9:10:66.153", G_format, true, "dontcare"); // seconds out of range
1116                 TryParseExactHelper ("3:9:10:12.153", G_format, true, "dontcare", french_culture); // fr-FR uses ',' as decimal separator
1117                 TryParseExactHelper ("3:9:10:12,153", G_format, false, "3.09:10:12.1530000", french_culture);
1118                 TryParseExactHelper ("  3:9:10:12.153  ", G_format, false, "3.09:10:12.1530000", us_culture);
1119                 TryParseExactHelper ("3:9:10:13.153", G_format, false, "3.09:10:13.1530000", us_culture, TimeSpanStyles.AssumeNegative);
1120
1121                 // c format
1122                 string [] c_format = new string [] { "c" };
1123                 TryParseExactHelper ("12", c_format, false, "12.00:00:00");
1124                 TryParseExactHelper ("12:11", c_format, false, "12:11:00");
1125                 TryParseExactHelper ("12:66", c_format, true, "dontcare");
1126                 TryParseExactHelper ("10.11:12", c_format, false, "10.11:12:00");
1127                 TryParseExactHelper ("10.11:12:13", c_format, false, "10.11:12:13");
1128                 TryParseExactHelper ("10:11:12:13", c_format, true, "dontcare"); // this is normally accepted in the Parse method
1129                 TryParseExactHelper ("10.11:12:13.6", c_format, false, "10.11:12:13.6000000");
1130                 TryParseExactHelper ("10:11:12,6", c_format, true, "dontcare");
1131                 TryParseExactHelper ("10:11:12,6", c_format, true, "dontcare", french_culture);
1132                 TryParseExactHelper ("  10:11:12.6  ", c_format, false, "10:11:12.6000000");
1133                 TryParseExactHelper ("10:12", c_format, false, "10:12:00", null, TimeSpanStyles.AssumeNegative);
1134                 TryParseExactHelper ("10:123456789999", c_format, true, "dontcare");
1135
1136                 TryParseExactHelper ("10:12", new string [0], true, "dontcare");
1137                 TryParseExactHelper ("10:12", new string [] { String.Empty }, true, "dontcare");
1138                 TryParseExactHelper ("10:12", new string [] { null }, true, "dontcare");
1139
1140                 TryParseExactHelper (null, new string [] { null }, true, "dontcare");
1141         }
1142
1143         void TryParseExactHelper (string input, string [] formats, bool error, string expected, IFormatProvider formatProvider = null,
1144                         TimeSpanStyles styles = TimeSpanStyles.None)
1145         {
1146                 TimeSpan result;
1147                 bool success;
1148
1149                 success = TimeSpan.TryParseExact (input, formats, formatProvider, styles, out result);
1150                 Assert.AreEqual (!error, success);
1151                 if (!error)
1152                         Assert.AreEqual (expected, result.ToString ());
1153         }
1154
1155         [Test]
1156         public void ParseExactExceptions ()
1157         {
1158                 try {
1159                         TimeSpan.ParseExact (null, "g", null);
1160                         Assert.Fail ("#A1");
1161                 } catch (ArgumentNullException) {
1162                 }
1163
1164                 try {
1165                         TimeSpan.ParseExact ("10:12", (string)null, null);
1166                         Assert.Fail ("#A2");
1167                 } catch (ArgumentNullException) {
1168                 }
1169
1170                 try {
1171                         TimeSpan.ParseExact ("10:12", (string [])null, null);
1172                         Assert.Fail ("#A3");
1173                 } catch (ArgumentNullException) {
1174                 }
1175         }
1176
1177         [Test]
1178         public void ToStringOverloads ()
1179         {
1180                 TimeSpan ts = new TimeSpan (1, 2, 3, 4, 6);
1181
1182                 // Simple version - culture invariant
1183                 Assert.AreEqual ("1.02:03:04.0060000", ts.ToString (), "#A1");
1184                 Assert.AreEqual ("1.02:03:04.0060000", ts.ToString ("c"), "#A2");
1185                 Assert.AreEqual ("1.02:03:04.0060000", ts.ToString (null), "#A3");
1186                 Assert.AreEqual ("1.02:03:04.0060000", ts.ToString (String.Empty), "#A4");
1187
1188                 //
1189                 // IFormatProvider ones - use a culture changing numeric format.
1190                 // Also, we use fr-FR as culture, since it uses some elements different to invariant culture
1191                 //
1192                 CultureInfo culture = CultureInfo.GetCultureInfo ("fr-FR");
1193
1194                 Assert.AreEqual ("1:2:03:04,006", ts.ToString ("g", culture), "#B1");
1195                 Assert.AreEqual ("1:02:03:04,0060000", ts.ToString ("G", culture), "#B2");
1196                 Assert.AreEqual ("1.02:03:04.0060000", ts.ToString ("c", culture), "#B3"); // 'c' format ignores CultureInfo
1197                 Assert.AreEqual ("1.02:03:04.0060000", ts.ToString ("t", culture), "#B4"); // 't' and 'T' are the same as 'c'
1198                 Assert.AreEqual("1.02:03:04.0060000", ts.ToString("T", culture), "#B5");
1199
1200                 ts = new TimeSpan (4, 5, 6);
1201                 Assert.AreEqual ("4:05:06", ts.ToString ("g", culture), "#C1");
1202                 Assert.AreEqual ("0:04:05:06,0000000", ts.ToString ("G", culture), "#C2");
1203         }
1204
1205         [Test]
1206         public void ToStringCustomFormats ()
1207         {
1208                 TimeSpan ts = new TimeSpan (1, 3, 5, 7);
1209
1210                 Assert.AreEqual ("1", ts.ToString ("%d"), "#A0");
1211                 Assert.AreEqual ("3", ts.ToString ("%h"), "#A1");
1212                 Assert.AreEqual ("5", ts.ToString ("%m"), "#A2");
1213                 Assert.AreEqual ("7", ts.ToString ("%s"), "#A3");
1214                 Assert.AreEqual ("0", ts.ToString ("%f"), "#A4");
1215                 Assert.AreEqual (String.Empty, ts.ToString ("%F"), "#A5"); // Nothing to display
1216
1217                 Assert.AreEqual ("01", ts.ToString ("dd"), "#B0");
1218                 Assert.AreEqual ("00000001", ts.ToString ("dddddddd"), "#B1");
1219                 Assert.AreEqual ("03", ts.ToString ("hh"), "#B2");
1220                 Assert.AreEqual ("05", ts.ToString ("mm"), "#B3");
1221                 Assert.AreEqual ("07", ts.ToString ("ss"), "#B4");
1222                 Assert.AreEqual ("00", ts.ToString ("ff"), "#B5");
1223                 Assert.AreEqual ("0000000", ts.ToString ("fffffff"), "#B6");
1224                 Assert.AreEqual (String.Empty, ts.ToString ("FF"), "#B7");
1225
1226                 Assert.AreEqual ("01;03;05", ts.ToString (@"dd\;hh\;mm"), "#C0");
1227                 Assert.AreEqual ("05 07", ts.ToString (@"mm\ ss"), "#C1");
1228                 Assert.AreEqual ("05 07 ", ts.ToString (@"mm\ ss\ FF"), "#C2");
1229                 Assert.AreEqual ("Result = 3 hours with 5 minutes and 7 seconds",
1230                                 ts.ToString (@"'Result = 'h' hours with 'm' minutes and 's' seconds'"), "#C3");
1231                 Assert.AreEqual ("  ", ts.ToString (@"\ \ "), "#C4");
1232
1233                 ts = new TimeSpan (1, 3, 5, 7, 153);
1234                 Assert.AreEqual ("1", ts.ToString ("%F"), "#D0");
1235                 Assert.AreEqual ("15", ts.ToString ("FF"), "#D1"); // Don't use %, as the parser gets confused here
1236                 Assert.AreEqual ("153", ts.ToString ("FFFFFFF"), "#D2");
1237
1238                 // Negative values are shown without sign
1239                 ts = new TimeSpan (-1, -3, -5);
1240                 Assert.AreEqual ("1", ts.ToString ("%h"), "#E0");
1241                 Assert.AreEqual ("3", ts.ToString ("%m"), "#E1");
1242                 Assert.AreEqual ("5", ts.ToString ("%s"), "#E2");
1243
1244                 ts = new TimeSpan (123456789);
1245                 Assert.AreEqual ("12.3", ts.ToString ("s\\.f"), "#F0");
1246                 Assert.AreEqual ("12.3", ts.ToString ("s\\.F"), "#F1");
1247                 Assert.AreEqual ("12.3456789", ts.ToString ("s\\.fffffff"), "#F2");
1248                 Assert.AreEqual ("12.345678", ts.ToString ("s\\.ffffff"), "#F3");
1249
1250                 ts = new TimeSpan (1234);
1251                 Assert.AreEqual ("0.000123", ts.ToString ("s\\.ffffff"), "#G0");
1252                 Assert.AreEqual ("0.0001", ts.ToString ("s\\.ffff"), "#G1");
1253                 Assert.AreEqual ("0.", ts.ToString ("s\\.F"), "#G2");
1254                 Assert.AreEqual ("0.", ts.ToString ("s\\.FFF"), "#G3");
1255
1256                 ts = TimeSpan.FromSeconds (0.05);
1257                 Assert.AreEqual (".0", ts.ToString ("\\.f"), "#H0");
1258                 Assert.AreEqual (".", ts.ToString ("\\.F"), "#H1");
1259         }
1260
1261         [Test]
1262         public void ToStringOverloadsErrors ()
1263         {
1264                 TimeSpan ts = new TimeSpan (10, 10, 10);
1265                 string result;
1266
1267                 try {
1268                         result = ts.ToString ("non-valid");
1269                         Assert.Fail ("#1");
1270                 } catch (FormatException) {
1271                 }
1272
1273                 try {
1274                         result = ts.ToString ("C");
1275                         Assert.Fail ("#2");
1276                 } catch (FormatException) {
1277                 }
1278
1279                 try
1280                 {
1281                         ts.ToString ("m");
1282                         Assert.Fail ("#3");
1283                 } catch (FormatException) {
1284                 }
1285
1286                 try
1287                 {
1288                         ts.ToString ("d"); // Missing % for single char
1289                         Assert.Fail ("#4");
1290                 } catch (FormatException)
1291                 {
1292                 }
1293
1294                 try
1295                 {
1296                         ts.ToString ("ddddddddd");
1297                         Assert.Fail ("#5");
1298                 } catch (FormatException)
1299                 {
1300                 }
1301
1302                 try
1303                 {
1304                         ts.ToString ("hhh");
1305                         Assert.Fail ("#5");
1306                 } catch (FormatException)
1307                 {
1308                 }
1309
1310                 try
1311                 {
1312                         ts.ToString ("ffffffff");
1313                         Assert.Fail ("6");
1314                 } catch (FormatException)
1315                 {
1316                 }
1317         }
1318 }
1319
1320 }