Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

487 lines
14 KiB
C#

//
// Copyright (c) 2006 Mainsoft Co.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.IO;
using System.Collections;
using NUnit.Framework;
namespace MonoTests.System.Data.Utils
{
public class GHTBase
{
#region Constructors
/// <summary>Constructor
/// <param name="Logger">Custom TextWriter to log to</param>
/// <param name="LogOnSuccess">False to log only failed TestCases, True to log all</param>
/// </summary>
protected GHTBase(TextWriter Logger, bool LogOnSuccess)
{
this._logger = Logger;
this._logOnSuccess = LogOnSuccess;
}
/// <summary>Constructor, log to Console
/// <param name="LogOnSuccess">False to log only failed TestCases, True to log all</param>
/// </summary>
protected GHTBase(bool LogOnSuccess):this(Console.Out, LogOnSuccess){}
/// <summary>Constructor, log to Console only when Failed
/// </summary>
protected GHTBase():this(Console.Out, false){}
#endregion
#region protected methods
public void GHTSetLogger(TextWriter Logger)
{
this._logger = Logger;
}
/// <summary>Begin Test which containes TestCases
/// <param name="testName">Test name, used on logs</param>
/// </summary>
public virtual void BeginTest(string testName)
{
//set test name
this._testName = testName;
//reset the Failure Counter and the TestCase Number
UniqueId.ResetCounters();
if(this._logOnSuccess == true)
Log(string.Format("*** Starting Test: [{0}] ***", this._testName));
}
/// <summary>Begin TestCase
/// <param name="Description">TestCase Description, used on logs</param>
/// </summary>
public void BeginCase(string Description)
{
//Previous TestCase must be ended before beginning a new one.
if (_testCase != null) throw new Exception("Previous Case not Ended");
//init the new TestCase with Unique TestCase Number and Description
_testCase = new UniqueId(Description);
if(this._logOnSuccess == true)
Log(string.Format("Starting Case: [{0}]", _testCase.ToString()));
}
/// <summary>Compare two objects (using Object.Equals)
/// </summary>
protected bool Compare(object a, object b)
{
Assert.AreEqual(b, a);
//signal that the Compare method has been called
this._testCase.CompareInvoked = true;
//a string that holds the description of the objects for log
string ObjectData;
//check if one of the objects is null
if (a == null && b != null)
{
ObjectData = "Object a = null" + ", Object b.ToString() = '" + b.ToString() + "'(" + b.GetType().FullName + ")";
this._testCase.Success = false; //objects are different, TestCase Failed
LogCompareResult(ObjectData);
return this._testCase.Success;
}
//check if the other object is null
if (a != null && b == null)
{
ObjectData = "Object a.ToString() = '" + a.ToString() + "'(" + a.GetType().FullName + "), Object b = null";
this._testCase.Success = false; //objects are different, TestCase Failed
LogCompareResult(ObjectData);
return this._testCase.Success;
}
//check if both objects are null
if ( (a == null && b == null) )
{
ObjectData = "Object a = null, Object b = null";
this._testCase.Success = true; //both objects are null, TestCase Succeed
LogCompareResult(ObjectData);
return this._testCase.Success;
}
ObjectData = "Object a.ToString() = '" + a.ToString() + "'(" + a.GetType().FullName + "), Object b.ToString = '" + b.ToString() + "'(" + b.GetType().FullName + ")";
//use Object.Equals to compare the objects
this._testCase.Success = (a.Equals(b));
LogCompareResult(ObjectData);
return this._testCase.Success;
}
/// <summary>Compare two Object Arrays.
/// <param name="a">First array.</param>
/// <param name="b">Second array.</param>
/// <param name="Sorted">Used to indicate if both arrays are sorted.</param>
/// </summary>
protected bool Compare(Array a, Array b)
{
Assert.AreEqual(b, a);
//signal that the Compare method has been called
this._testCase.CompareInvoked=true;
//a string that holds the description of the objects for log
string ObjectData;
//check if both objects are null
if ( (a == null && b == null) )
{
ObjectData = "Array a = null, Array b = null";
this._testCase.Success = true; //both objects are null, TestCase Succeed
LogCompareResult(ObjectData);
return this._testCase.Success;
}
//Check if one of the objects is null.
//(If both were null, we wouldn't have reached here).
if (a == null || b == null)
{
string aData = (a==null) ? "null" : "'" + a.ToString() + "' (" + a.GetType().FullName + ")";
string bData = (b==null) ? "null" : "'" +b.ToString() + "' (" + b.GetType().FullName + ")";
ObjectData = "Array a = " + aData + ", Array b = " + bData;
this._testCase.Success = false; //objects are different, testCase Failed.
LogCompareResult(ObjectData);
return this._testCase.Success;
}
//check if both arrays are of the same rank.
if (a.Rank != b.Rank)
{
this._testCase.Success = false;
ObjectData = string.Format("Array a.Rank = {0}, Array b.Rank = {1}", a.Rank, b.Rank);
LogCompareResult(ObjectData);
return this._testCase.Success;
}
//Do not handle multi dimentional arrays.
if (a.Rank != 1)
{
this._testCase.Success = false;
ObjectData = "Multi-dimension array comparison is not supported";
LogCompareResult(ObjectData);
return this._testCase.Success;
}
//Check if both arrays are of the same length.
if (a.Length != b.Length)
{
this._testCase.Success = false;
ObjectData = string.Format("Array a.Length = {0}, Array b.Length = {1}", a.Length, b.Length);
LogCompareResult(ObjectData);
return this._testCase.Success;
}
ObjectData = "Array a.ToString() = '" + a.ToString() + "'(" + a.GetType().FullName + ") Array b.ToString = '" + b.ToString() + "'(" + b.GetType().FullName + ")";
//Compare elements of the Array.
int iLength = a.Length;
for (int i=0; i<iLength; i++)
{
object aValue = a.GetValue(i);
object bValue = b.GetValue(i);
if (aValue == null && bValue == null)
{
continue;
}
if (aValue == null || bValue == null || !aValue.Equals(bValue) )
{
string aData = (aValue==null) ? "null" : "'" + aValue.ToString() + "' (" + aValue.GetType().FullName + ")";
string bData = (bValue==null) ? "null" : "'" + bValue.ToString() + "' (" + bValue.GetType().FullName + ")";
ObjectData = string.Format("Array a[{0}] = {1}, Array b[{0}] = {2}", i, aData, bData);
this._testCase.Success = false; //objects are different, testCase Failed.
LogCompareResult(ObjectData);
return this._testCase.Success;
}
}
this._testCase.Success = true;
LogCompareResult(ObjectData);
return this._testCase.Success;
}
/// <summary>
/// Intentionally fail a testcase, without calling the compare method.
/// </summary>
/// <param name="message">The reason for the failure.</param>
protected void Fail(string message)
{
this._testCase.CompareInvoked = true;
this._testCase.Success = false;
//Log(string.Format("TestCase \"{0}\" Failed: [{1}]", _testCase.ToString(), message));
Assert.Fail(message);
}
/// <summary>
/// Intentionally cause a testcase to pass, without calling the compare message.
/// </summary>
/// <param name="message">The reason for passing the test.</param>
protected void Pass(string message)
{
this._testCase.CompareInvoked = true;
this._testCase.Success = true;
if (this._logOnSuccess)
{
Log(string.Format("TestCase \"{0}\" Passed: [{1}]", _testCase.ToString(), message));
}
}
/// <summary>
/// Marks this testcase as success, but logs the reason for skipping regardless of _logOnSuccess value.
/// </summary>
/// <param name="message">The reason for skipping the test.</param>
protected void Skip(string message)
{
this._testCase.CompareInvoked = true;
this._testCase.Success = true;
Log(string.Format("TestCase \"{0}\" Skipped: [{1}]", _testCase.ToString(), message));
}
/// <summary>
/// Intentionally fail a testcase when an expected exception is not thrown.
/// </summary>
/// <param name="exceptionName">The name of the expected exception type.</param>
protected void ExpectedExceptionNotCaught(string exceptionName)
{
this.Fail(string.Format("Expected {0} was not caught.", exceptionName));
}
/// <summary>
/// Intentionally cause a testcase to pass, when an expected exception is thrown.
/// </summary>
/// <param name="ex"></param>
protected void ExpectedExceptionCaught(Exception ex)
{
this.Pass(string.Format("Expected {0} was caught.", ex.GetType().FullName));
}
/// <summary>End TestCase
/// <param name="ex">Exception object if exception occured during the TestCase, null if not</param>
/// </summary>
protected void EndCase(Exception ex)
{
//check if BeginCase was called. cannot end an unopen TestCase
if(_testCase == null)
{
throw new Exception("BeginCase was not called");
}
else
{
//if Exception occured during the test - log the error and faile the TestCase.
if(ex != null)
{
_testCase.Success=false;
Log(string.Format("TestCase: \"{0}\" Error: [Failed With Unexpected {1}: \n\t{2}]", _testCase.ToString(), ex.GetType().FullName, ex.Message + "\n" + ex.StackTrace ));
_testCase = null;
throw ex;
}
else
{
//check if Compare was called
if (_testCase.CompareInvoked == true)
{
if(this._logOnSuccess == true) Log(string.Format("Finished Case: [{0}] ", _testCase.ToString()));
}
else
{
//if compare was not called, log error message
Log(string.Format("TestCase \"{0}\" Warning: [TestCase didn't invoke the Compare mehtod] ", _testCase.ToString()));
}
}
//Terminate TestCase (set TestCase to null)
_testCase = null;
}
}
/// <summary>End Test
/// <param name="ex">Exception object if exception occured during the Test, null if not</param>
/// </summary>
public void EndTest(Exception ex)
{
//if all test cases succeeded but an exception occured - set exit code to -1
//if we wont set it to -1, the exit code will be 0 !!!
if (UniqueId.FailureCounter == 0 && ex != null)
{
Environment.ExitCode = -1;
}
else
{
//set exitcode to the count of failed TestCases
Environment.ExitCode = UniqueId.FailureCounter;
}
//if exception occured - log error
if(ex != null)
{
Log(string.Format("Unexpected Exception accured in Test [{0}] - {1} \n {2}" , this._testName, ex.Message ,ex.StackTrace));
}
if(this._logOnSuccess)
{
Log(string.Format("*** Finished Test: [{0}] ***", this._testName));
}
}
public int GHTGetExitCode()
{
return UniqueId.FailureCounter;
}
/// <summary>logger
/// <param name="text">string message to log</param>
/// </summary>
protected void Log(string text)
{
// _loggerBuffer = _loggerBuffer + "\n" + "GHTBase:Logger - " + text;
// _logger.WriteLine("GHTBase:Logger - " + text);
}
//used to log the results from the compare methods
private void LogCompareResult(string ObjectData)
{
if(this._testCase.Success == false)
{
Log(string.Format("TeseCase \"{0}\" Error: [Failed while comparing(" + ObjectData + ")] ", _testCase.ToString() ));
}
else
if(this._logOnSuccess == true)
Log(string.Format("TestCase \"{0}\" Passed ", _testCase.ToString()));
}
protected int TestCaseNumber
{
get
{
return _testCase.CaseNumber;
}
}
#endregion
#region private fields
private TextWriter _logger;
public string _loggerBuffer; // a public clone string of the _logger (used in web tests)
private string _testName;
private UniqueId _testCase;
private bool _logOnSuccess;
#endregion
}
//holds all the info on a TestCase
internal class UniqueId
{
//holds the unique name of the test case
//this name must be recieved from the test case itself
//when calling BeginCase.
//example: BeginCase("MyName")
private string _caseName;
//maintains the number generated for this test case
private static int _caseNumber;
//maintains the number of failed test case
private static int _FailureCounter;
internal static int FailureCounter
{
get
{
return _FailureCounter;
}
}
//indicate if the Compare method has been invoked AND containes compare objects message (ToString)
private bool _CompareInvoked;
internal bool CompareInvoked
{
get
{
return _CompareInvoked;
}
set
{
_CompareInvoked = value;
}
}
//reset the static counters when a new Test (not TestCase !!) begin
internal static void ResetCounters()
{
_FailureCounter = 0;
_caseNumber = 0;
}
//signal if a TestCase failed, if failed - increment the _FailureCounter
private bool _success;
internal bool Success
{
get
{
return this._success;
}
set
{
this._success = value;
if (value == false)
{
_FailureCounter++;
}
}
}
//Ctor, Recieve the name for the test case
//generate a unique number and apply it to the test case
internal UniqueId(string Name)
{
this._caseName = Name;
//this._caseNumber = ++UniqueId._counter;
_caseNumber++;
}
internal int CaseNumber
{
get
{
return _caseNumber;
}
}
public override string ToString()
{
return string.Format("\"{0}\" #{1}", this._caseName, _caseNumber);
}
}
}