Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mcs / class / System.Data / Test / System.Data.Tests.Mainsoft / GHTUtils / GHTBase.cs
1 // Authors:
2 //   Rafael Mizrahi   <rafim@mainsoft.com>
3 //   Erez Lotan       <erezl@mainsoft.com>
4 //   Oren Gurfinkel   <oreng@mainsoft.com>
5 //   Ofer Borstein
6 // 
7 // Copyright (c) 2004 Mainsoft Co.
8 // 
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using System;
30 using System.IO;
31 using System.Collections;
32 using NUnit.Framework;
33
34 namespace GHTUtils.Base
35 {
36         public class GHTBase
37         {
38                 #region Constructors    
39                 /// <summary>Constructor 
40                 /// <param name="Logger">Custom TextWriter to log to</param>
41                 /// <param name="LogOnSuccess">False to log only failed TestCases, True to log all</param>
42                 /// </summary>
43                 protected GHTBase(TextWriter Logger, bool LogOnSuccess)
44                 {
45                         this._logger = Logger;
46                         this._logOnSuccess = LogOnSuccess;
47                         this._testName = this.GetType().Name;
48                 }
49
50                 /// <summary>Constructor, log to Console
51                 /// <param name="LogOnSuccess">False to log only failed TestCases, True to log all</param>
52                 /// </summary>
53                 protected GHTBase(bool LogOnSuccess):this(Console.Out, LogOnSuccess){}
54
55                 /// <summary>Constructor, log to Console only when Failed 
56                 /// </summary>
57                 protected GHTBase():this(Console.Out, false){}
58                 #endregion
59
60                 #region protected methods
61
62                 public void GHTSetLogger(TextWriter Logger)
63                 {
64                         this._logger = Logger;
65                 }
66                 /// <summary>Begin Test which containes TestCases
67                 /// <param name="testName">Test name, used on logs</param>
68                 /// </summary>
69                 public virtual void BeginTest(string testName)
70                 {
71                         //set test name
72                         this._testName = testName;
73                         //reset the Failure Counter and the TestCase Number
74                         UniqueId.ResetCounters();
75
76                         if(this._logOnSuccess == true)
77                                 Log(string.Format("*** Starting Test: [{0}] ***", this._testName));
78                 }
79
80                 /// <summary>Begin TestCase
81                 /// <param name="Description">TestCase Description, used on logs</param>
82                 /// </summary>
83                 public void BeginCase(string Description)
84                 {
85                         //init the new TestCase with Unique TestCase Number and Description
86                         _testCase = new UniqueId(Description);
87
88                         if(this._logOnSuccess == true)
89                                 Log(string.Format("Starting Case: [{0}]", _testCase.ToString()));
90                 }
91
92
93                 /// <summary>Compare two objects (using Object.Equals)
94                 /// </summary>
95                 protected bool Compare(object a, object b)
96                 {
97                         //signal that the Compare method has been called
98                         if (_testCase == null) {
99                                 _testCase = new UniqueId(_testName);
100                         }
101                         this._testCase.CompareInvoked = true;
102                         //a string that holds the description of the objects for log
103                         string ObjectData;
104
105                         //check if one of the objects is null
106                         if  (a == null && b != null)
107                         {
108                                 ObjectData = "Object a = null" + ", Object b.ToString() = '" + b.ToString() + "'(" + b.GetType().FullName + ")";
109                                 this._testCase.Success = false; //objects are different, TestCase Failed
110                                 LogCompareResult(ObjectData);
111                                 return this._testCase.Success;
112                         }
113
114                         //check if the other object is null
115                         if  (a != null && b == null)
116                         {
117                                 ObjectData = "Object a.ToString() = '" + a.ToString() + "'(" + a.GetType().FullName + "), Object b = null";
118                                 this._testCase.Success = false; //objects are different, TestCase Failed
119                                 LogCompareResult(ObjectData);
120                                 return this._testCase.Success;
121                         }
122
123                         //check if both objects are null
124                         if ( (a == null && b == null) )
125                         {
126                                 ObjectData = "Object a = null, Object b = null";
127                                 this._testCase.Success = true; //both objects are null, TestCase Succeed
128                                 LogCompareResult(ObjectData);
129                                 return this._testCase.Success;
130                         }
131
132                         ObjectData = "Object a.ToString() = '" + a.ToString() + "'(" + a.GetType().FullName + "), Object b.ToString = '" + b.ToString() + "'(" + b.GetType().FullName + ")";
133                         //use Object.Equals to compare the objects
134                         this._testCase.Success = (a.Equals(b));
135                         LogCompareResult(ObjectData);
136                         return this._testCase.Success;
137                 }
138
139                 /// <summary>Compare two Object Arrays. 
140                 /// <param name="a">First array.</param>
141                 /// <param name="b">Second array.</param>
142                 /// <param name="Sorted">Used to indicate if both arrays are sorted.</param>
143                 /// </summary>
144                 protected bool Compare(Array a, Array b)
145                 {
146                         //signal that the Compare method has been called
147                         this._testCase.CompareInvoked=true;
148                         //a string that holds the description of the objects for log
149                         string ObjectData;
150
151                         //check if both objects are null
152                         if ( (a == null && b == null) )
153                         {
154                                 ObjectData = "Array a = null, Array b = null";
155                                 this._testCase.Success = true; //both objects are null, TestCase Succeed
156                                 LogCompareResult(ObjectData);
157                                 return this._testCase.Success;
158                         }
159
160                         //Check if one of the objects is null.
161                         //(If both were null, we wouldn't have reached here).
162                         if (a == null || b == null)
163                         {
164                                 string aData = (a==null) ? "null" : "'" + a.ToString() + "' (" + a.GetType().FullName + ")";
165                                 string bData = (b==null) ? "null" : "'" +b.ToString() + "' (" + b.GetType().FullName + ")";
166                                 ObjectData = "Array a = "  + aData + ", Array b = " + bData;
167                                 this._testCase.Success = false; //objects are different, testCase Failed.
168                                 LogCompareResult(ObjectData);
169                                 return this._testCase.Success;
170                         }
171
172                         //check if both arrays are of the same rank.
173                         if (a.Rank != b.Rank)
174                         {
175                                 this._testCase.Success = false;
176                                 ObjectData = string.Format("Array a.Rank = {0}, Array b.Rank = {1}", a.Rank, b.Rank);
177                                 LogCompareResult(ObjectData);
178                                 return this._testCase.Success;
179                         }
180
181                         //Do not handle multi dimentional arrays.
182                         if (a.Rank != 1)
183                         {
184                                 this._testCase.Success = false;
185                                 ObjectData = "Multi-dimension array comparison is not supported";
186                                 LogCompareResult(ObjectData);
187                                 return this._testCase.Success;
188                         }
189
190                         //Check if both arrays are of the same length.
191                         if (a.Length != b.Length)
192                         {
193                                 this._testCase.Success = false;
194                                 ObjectData = string.Format("Array a.Length = {0}, Array b.Length = {1}", a.Length, b.Length);
195                                 LogCompareResult(ObjectData);
196                                 return this._testCase.Success;
197                         }
198
199                         ObjectData = "Array a.ToString() = '" + a.ToString() + "'(" + a.GetType().FullName + ") Array b.ToString = '" + b.ToString() + "'(" + b.GetType().FullName + ")";
200
201                         //Compare elements of the Array.
202                         int iLength = a.Length;
203                         for (int i=0; i<iLength; i++)
204                         {
205                                 object aValue = a.GetValue(i);
206                                 object bValue = b.GetValue(i);
207
208                                 if (aValue == null && bValue == null)
209                                 {
210                                         continue;
211                                 }
212
213                                 if (aValue == null || bValue == null  ||  !aValue.Equals(bValue) )
214                                 {
215                                         string aData = (aValue==null) ? "null" : "'" + aValue.ToString() + "' (" + aValue.GetType().FullName + ")";
216                                         string bData = (bValue==null) ? "null" : "'" + bValue.ToString() + "' (" + bValue.GetType().FullName + ")";
217                                         ObjectData = string.Format("Array a[{0}] = {1}, Array b[{0}] = {2}", i, aData, bData);
218                                         this._testCase.Success = false; //objects are different, testCase Failed.
219                                         LogCompareResult(ObjectData);
220                                         return this._testCase.Success;
221                                 }
222                         }
223
224
225                         this._testCase.Success = true;
226                         LogCompareResult(ObjectData);
227                         return this._testCase.Success;
228                 }
229         
230
231                 /// <summary>
232                 /// Intentionally fail a testcase, without calling the compare method.
233                 /// </summary>
234                 /// <param name="message">The reason for the failure.</param>
235                 protected void Fail(string message)
236                 {
237                         this._testCase.CompareInvoked = true;
238                         this._testCase.Success = false;
239                         string msg = string.Format("TestCase \"{0}\" Failed: [{1}]", _testCase.ToString(), message);
240                         if (_failAtTestEnd == null)
241                                 Assert.Fail(msg);
242                         Log(msg);
243                 }
244
245                 /// <summary>
246                 /// Intentionally cause a testcase to pass, without calling the compare message.
247                 /// </summary>
248                 /// <param name="message">The reason for passing the test.</param>
249                 protected void Pass(string message)
250                 {
251                         this._testCase.CompareInvoked = true;
252                         this._testCase.Success = true;
253                         if (this._logOnSuccess)
254                         {
255                                 Log(string.Format("TestCase \"{0}\" Passed: [{1}]", _testCase.ToString(), message));
256                         }
257                 }
258
259                 /// <summary>
260                 /// Marks this testcase as success, but logs the reason for skipping regardless of _logOnSuccess value.
261                 /// </summary>
262                 /// <param name="message">The reason for skipping the test.</param>
263                 protected void Skip(string message)
264                 {
265                         this._testCase.CompareInvoked = true;
266                         this._testCase.Success = true;
267                         Log(string.Format("TestCase \"{0}\" Skipped: [{1}]", _testCase.ToString(), message));
268                 }
269
270                 /// <summary>
271                 /// Intentionally fail a testcase when an expected exception is not thrown.
272                 /// </summary>
273                 /// <param name="exceptionName">The name of the expected exception type.</param>
274                 protected void ExpectedExceptionNotCaught(string exceptionName)
275                 {
276                         this.Fail(string.Format("Expected {0} was not caught.", exceptionName));
277                 }
278
279                 /// <summary>
280                 /// Intentionally cause a testcase to pass, when an expected exception is thrown.
281                 /// </summary>
282                 /// <param name="ex"></param>
283                 protected void ExpectedExceptionCaught(Exception ex)
284                 {
285                         this.Pass(string.Format("Expected {0} was caught.", ex.GetType().FullName));
286                 }
287
288                 /// <summary>End TestCase
289                 /// <param name="ex">Exception object if exception occured during the TestCase, null if not</param>
290                 /// </summary>
291                 protected void EndCase(Exception ex)
292                 {
293                         //check if BeginCase was called. cannot end an unopen TestCase
294                         if(_testCase == null)
295                         {
296                                 throw new Exception("BeginCase was not called");
297                         }
298                         else
299                         {
300                                 // if Exception occured during the test - log the error and faile the TestCase.
301                                 if(ex != null)
302                                 {
303                                         _testCase.Success=false;
304                                         if (_failAtTestEnd == null)
305                                                 throw ex;
306                                         Log(string.Format("TestCase: \"{0}\" Error: [Failed With Unexpected {1}: \n\t{2}]", _testCase.ToString(), ex.GetType().FullName, ex.Message + "\n" + ex.StackTrace ));
307                                 }
308                                 else
309                                 {                    
310                                         //check if Compare was called
311                                         if (_testCase.CompareInvoked == true)
312                                         {
313                                                 if(this._logOnSuccess == true) Log(string.Format("Finished Case: [{0}] ", _testCase.ToString()));
314                                         }
315                                         else
316                                         {
317                                                 //if compare was not called, log error message
318                                                 //Log(string.Format("TestCase \"{0}\" Warning: [TestCase didn't invoke the Compare mehtod] ", _testCase.ToString()));
319                                         }
320                                 }
321                                 //Terminate TestCase (set TestCase to null)
322                                 _testCase = null;
323                         }
324                 }
325
326
327                 /// <summary>End Test
328                 /// <param name="ex">Exception object if exception occured during the Test, null if not</param>
329                 /// </summary>
330                 public void EndTest(Exception ex)
331                 {
332                         if (ex != null) 
333                                 throw ex;
334                         else if (UniqueId.FailureCounter != 0)
335                                 Assert.Fail(String.Format("Test {0} failed in {1} scenarios.", this._testName, UniqueId.FailureCounter));
336
337                         if(this._logOnSuccess)
338                         {
339                                 Log(string.Format("*** Finished Test: [{0}] ***", this._testName));
340                         }
341                 }
342         
343
344                 public int GHTGetExitCode()
345                 {
346                         return UniqueId.FailureCounter;
347                 }
348
349                 /// <summary>logger 
350                 /// <param name="text">string message to log</param>
351                 /// </summary>
352                 protected void Log(string text)
353                 {
354                         _loggerBuffer = _loggerBuffer + "\n" + "GHTBase:Logger - " + text;
355                         _logger.WriteLine("GHTBase:Logger - " + text);
356                 }
357
358                 //used to log the results from the compare methods
359                 private void LogCompareResult(string ObjectData)
360                 {
361                         if(this._testCase.Success == false)
362                         {
363                                 string msg = string.Format("TeseCase \"{0}\" Error: [Failed while comparing(" + ObjectData + ")] ", _testCase.ToString() );
364                                 if (_failAtTestEnd == null)
365                                         Assert.Fail(msg);
366                                 Log("Test: " + _testName + " " + msg);
367                         }
368                         else if(this._logOnSuccess == true)
369                                 Log(string.Format("TestCase \"{0}\" Passed ", _testCase.ToString()));
370                         
371                 }
372
373                 protected int TestCaseNumber
374                 {
375                         get
376                         {
377                                 return _testCase.CaseNumber;
378                         }
379                 }
380
381                 #endregion
382
383                 #region private fields
384                 
385                 private TextWriter _logger;
386                 public string _loggerBuffer; // a public clone string of the _logger (used in web tests)
387
388                 private string _testName;
389                 private UniqueId _testCase;
390                 private bool _logOnSuccess;
391                 private string _failAtTestEnd = Environment.GetEnvironmentVariable("MONOTEST_FailAtTestEnd");
392                 #endregion
393                 
394         }
395
396         //holds all the info on a TestCase
397         internal class UniqueId
398         {
399                 //holds the unique name of the test case
400                 //this name must be recieved from the test case itself
401                 //when calling BeginCase.
402                 //example: BeginCase("MyName")
403                 private string _caseName;
404
405                 //maintains the number generated for this test case
406                 private static int _caseNumber;
407
408                 //maintains the number of failed test case 
409                 private static int _FailureCounter;
410                 internal static int FailureCounter
411                 {
412                         get
413                         {
414                                 return _FailureCounter;
415                         }
416                 }
417                 
418                 //indicate if the Compare method has been invoked AND containes compare objects message (ToString)
419                 private bool _CompareInvoked;
420                 internal bool CompareInvoked
421                 {
422                         get
423                         {
424                                 return _CompareInvoked;
425                         }
426                         set
427                         {
428                                 _CompareInvoked = value;
429                         }
430                 }
431
432
433                 //reset the static counters when a new Test (not TestCase !!) begin
434                 internal static void ResetCounters()
435                 {
436                         _FailureCounter = 0;
437                         _caseNumber = 0;
438                 }
439
440                 //signal if a TestCase failed, if failed - increment the _FailureCounter
441                 private bool _success;
442                 internal bool Success
443                 {
444                         get
445                         {
446                                 return this._success;
447                         }
448                         set
449                         {
450                                 this._success = value;
451
452                                 if (value == false) 
453                                 {
454                                         _FailureCounter++;
455                                 }
456                         }
457                 }
458
459
460                 //Ctor, Recieve the name for the test case
461                 //generate a unique number and apply it to the test case
462                 internal UniqueId(string Name)
463                 {
464                         this._caseName = Name;
465                         //this._caseNumber = ++UniqueId._counter;
466                         _caseNumber++;
467                 }
468
469                 internal int CaseNumber
470                 {
471                         get
472                         {
473                                 return _caseNumber;
474                         }
475                 }
476
477                 public override string ToString()
478                 {
479                         return string.Format("{0} #{1}", this._caseName, _caseNumber);
480                 }
481         }
482 }