a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
487 lines
14 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|