GHTBase.cs 14 KB

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