TestFramework.pas
上传用户:yjb1804
上传日期:2021-01-30
资源大小:3105k
文件大小:81k
源码类别:

Email服务器

开发平台:

Delphi

  1. {#(@)$Id: TestFramework.pas,v 1.117 2006/07/19 02:45:55 judc Exp $ }
  2. {  DUnit: An XTreme testing framework for Delphi programs. }
  3. (*
  4.  * The contents of this file are subject to the Mozilla Public
  5.  * License Version 1.1 (the "License"); you may not use this file
  6.  * except in compliance with the License. You may obtain a copy of
  7.  * the License at http://www.mozilla.org/MPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS
  10.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  11.  * implied. See the License for the specific language governing
  12.  * rights and limitations under the License.
  13.  *
  14.  * The Original Code is DUnit.
  15.  *
  16.  * The Initial Developers of the Original Code are Kent Beck, Erich Gamma,
  17.  * and Juancarlo A馿z.
  18.  * Portions created The Initial Developers are Copyright (C) 1999-2000.
  19.  * Portions created by The DUnit Group are Copyright (C) 2000-2004.
  20.  * All rights reserved.
  21.  *
  22.  * Contributor(s):
  23.  * Kent Beck <kentbeck@csi.com>
  24.  * Erich Gamma <Erich_Gamma@oti.com>
  25.  * Juanco A馿z <juanco@users.sourceforge.net>
  26.  * Chris Morris <chrismo@users.sourceforge.net>
  27.  * Jeff Moore <JeffMoore@users.sourceforge.net>
  28.  * Uberto Barbini <uberto@usa.net>
  29.  * Brett Shearer <BrettShearer@users.sourceforge.net>
  30.  * Kris Golko <neuromancer@users.sourceforge.net>
  31.  * The DUnit group at SourceForge <http://dunit.sourceforge.net>
  32.  *
  33.  *)
  34. {$IFDEF CLR}
  35.   {$UNSAFECODE ON}
  36. {$ENDIF}
  37. {$BOOLEVAL OFF}
  38. unit TestFramework;
  39. interface
  40. uses
  41. {$IFDEF CLR}
  42.   System.Reflection,
  43. {$ENDIF}
  44.   SysUtils,
  45.   Classes,
  46.   IniFiles;
  47. const
  48.   rcs_id: string = '#(@)$Id: TestFramework.pas,v 1.117 2006/07/19 02:45:55 judc Exp $';
  49.   rcs_version : string = '$Revision: 1.117 $';
  50. type
  51. {$IFDEF CLR}
  52. //  Pointer = Borland.Delphi.System.Pointer;
  53.   IUnknown = interface(IInterface)
  54.   end;
  55.   TestAttribute = class(TCustomAttribute)
  56.   end;
  57. {$ENDIF}
  58. {$IFDEF CLR}
  59.   TTestMethod  = string;
  60. {$ELSE}
  61.   TTestMethod  = procedure of object;
  62. {$ENDIF}
  63.   TTestProc    = procedure;
  64.   TTestCaseClass  = class of TTestCase;
  65.   ITestListener   = interface;
  66.   IStatusListener = interface;
  67.   TTestResult   = class;
  68.   TAbstractTest = class;
  69.   TTestCase     = class;
  70.   TTestSuite    = class;
  71.   TTestFailure  = class;
  72.   ExceptionClass = class of Exception;
  73.   ETestFailure = class(EAbort)
  74.      constructor Create;               overload;
  75.      constructor Create(msg :string);  overload;
  76.   end;
  77.   EDunitException = class(Exception);
  78.   ETestError = class(EDunitException);
  79.   EStopTestsFailure = class(ETestFailure);
  80.   EPostTestFailure = class(ETestFailure);
  81.   TAllowedLeakArray = array[0..3] of integer;
  82.   TListIterator = function: integer of object;
  83.   IMemLeakMonitor = interface(IUnknown)
  84.   ['{041368CC-5B04-4111-9E2E-05A5908B3A58}']
  85.     function MemLeakDetected(out LeakSize: Integer): Boolean;
  86.   end;
  87.   IDUnitMemLeakMonitor = interface(IMemLeakMonitor)
  88.   ['{45466FCA-1ADC-4457-A41C-88FA3F8D23F7}']
  89.     function MemLeakDetected(const AllowedLeakSize: Integer;
  90.                              const FailOnMemoryRecovery: Boolean;
  91.                              out   LeakSize: Integer): Boolean; overload;
  92.     function MemLeakDetected(const AllowedValuesGetter: TListIterator;
  93.                              const FailOnMemoryRecovery: Boolean;
  94.                              out   LeakIndex: integer;
  95.                              out   LeakSize: Integer): Boolean; overload;
  96.     function GetMemoryUseMsg(const FailOnMemoryRecovery: Boolean;
  97.                              const TestProcChangedMem: Integer;
  98.                              out   ErrorMsg: string): Boolean; overload;
  99.     function GetMemoryUseMsg(const FailOnMemoryRecovery: boolean;
  100.                              const TestSetupChangedMem: Integer;
  101.                              const TestProcChangedMem: Integer;
  102.                              const TestTearDownChangedMem: Integer;
  103.                              const TestCaseChangedMem: Integer;
  104.                              out   ErrorMsg: string): boolean; overload;
  105.     procedure MarkMemInUse;
  106.   end;
  107.   { thrown to force a debugger break on a test failure }
  108.   EBreakingTestFailure = class(EDunitException)
  109.      constructor Create;               overload;
  110.      constructor Create(msg :string);  overload;
  111.   end;
  112.   ITest = interface(IUnknown)
  113.     ['{89CCD557-7DE1-4814-B033-ABAFE0870EC7}']
  114.     function GetName: string;
  115.     function  CountTestCases: integer;
  116.     function  CountEnabledTestCases: integer;
  117.     function  Tests: IInterfaceList;
  118.     procedure SetUp;
  119.     procedure TearDown;
  120.     function  Run : TTestResult;  overload;
  121.     procedure Run(testResult: TTestResult); overload;
  122.     procedure RunWithFixture(testResult: TTestResult);
  123.     procedure RunTest(testResult: TTestResult);
  124.     function  GetTestMethodInvoked: Boolean;
  125.     procedure SetTestMethodInvoked(const Value: Boolean);
  126.     property  TestMethodInvoked: Boolean read  GetTestMethodInvoked
  127.                                          write SetTestMethodInvoked;
  128.     function  GetEnabled: Boolean;
  129.     procedure SetEnabled(Value: Boolean);
  130.     procedure SetStartTime(Value :Int64);
  131.     function  GetStartTime : Int64;
  132.     procedure SetStopTime(Value :Int64);
  133.     function  GetStopTime : Int64;
  134.     function  ElapsedTestTime: Cardinal;
  135.     procedure SetStatusListener(Listener :IStatusListener);
  136.     function  GetStatus :string;
  137.     procedure LoadConfiguration(const iniFile :TCustomIniFile; const section :string);  overload;
  138.     procedure LoadConfiguration(const fileName: string; const useRegistry, useMemIni: Boolean); overload;
  139.     procedure SaveConfiguration(const iniFile :TCustomIniFile; const section :string);  overload;
  140.     procedure SaveConfiguration(const fileName: string; const useRegistry, useMemIni: Boolean); overload;
  141.     procedure SetGUIObject(const guiObject: TObject);
  142.     function  GetGUIObject: TObject;
  143.     property Name:    string  read GetName;
  144.     property Enabled: Boolean read GetEnabled write SetEnabled;
  145.     property GUIObject: TObject read GetGUIObject write SetGUIObject;
  146.     property Status:  string  read GetStatus;
  147.     property StartTime: Int64 read GetStartTime write SetStartTime;
  148.     property StopTime:  Int64 read GetStopTime  write SetStopTime;
  149.     procedure SetFailsOnNoChecksExecuted(const Value: Boolean);
  150.     function  GetFailsOnNoChecksExecuted: Boolean;
  151.     property  FailsOnNoChecksExecuted: Boolean
  152.                 read GetFailsOnNoChecksExecuted
  153.                 write SetFailsOnNoChecksExecuted;
  154.     function  GetFailsOnMemoryLeak: Boolean;
  155.     procedure SetFailsOnMemoryLeak(const Value: Boolean);
  156.     property  FailsOnMemoryLeak: Boolean
  157.                 read GetFailsOnMemoryLeak
  158.                 write SetFailsOnMemoryLeak;
  159.     function  GetAllowedMemoryLeakSize: Integer;
  160.     procedure SetAllowedMemoryLeakSize(const NewSize: Integer);
  161.     property  AllowedMemoryLeakSize: Integer read GetAllowedMemoryLeakSize
  162.                                            write SetAllowedMemoryLeakSize;
  163.     function  GetFailsOnMemoryRecovery: Boolean;
  164.     procedure SetFailsOnMemoryRecovery(const Value: Boolean);
  165.     property  FailsOnMemoryRecovery: Boolean
  166.                 read GetFailsOnMemoryRecovery
  167.                 write SetFailsOnMemoryRecovery;
  168.     procedure SetAllowedLeakArray(AllowedList: array of Integer);
  169.     function  GetIgnoreSetUpTearDownLeaks: Boolean;
  170.     procedure SetIgnoreSetUpTearDownLeaks(const Value: Boolean);
  171.     property  IgnoreSetUpTearDownLeaks: Boolean
  172.                 read GetIgnoreSetUpTearDownLeaks
  173.                 write SetIgnoreSetUpTearDownLeaks;
  174.     function  GetAllowedLeak: Integer;
  175.     function  GetAllowedLeaksIterator: TListIterator;
  176.     property  AllowedLeaksIterator: TListIterator read GetAllowedLeaksIterator;
  177.   end;
  178.   {: General interface for test decorators}
  179.   ITestDecorator = interface(ITest)
  180.     ['{8B3FC229-3033-4590-AD5C-01914C6E2C9F}']
  181.     {: Get the decorated test
  182.     @return The decorated test }
  183.     function GetTest: ITest;
  184.     property Test: ITest read GetTest;
  185.   end;
  186.   { IStatusListeners are notified of test status messages }
  187.   IStatusListener = interface
  188.   ['{8681DC88-033C-4A42-84F4-4C52EF9ABAC0}']
  189.     procedure Status(test :ITest; const Msg :string);
  190.   end;
  191.   { ITestListeners get notified of testing events.
  192.     See TTestResult.AddListener()
  193.   }
  194.   ITestListener = interface(IStatusListener)
  195.     ['{114185BC-B36B-4C68-BDAB-273DBD450F72}']
  196.     procedure TestingStarts;
  197.     procedure StartTest(test: ITest);
  198.     procedure AddSuccess(test: ITest);
  199.     procedure AddError(error: TTestFailure);
  200.     procedure AddFailure(Failure: TTestFailure);
  201.     procedure EndTest(test: ITest);
  202.     procedure TestingEnds(testResult :TTestResult);
  203.     function  ShouldRunTest(test :ITest):Boolean;
  204.   end;
  205.   ITestListenerX = interface(ITestListener)
  206.     ['{5C28B1BE-38B5-4D6F-AA96-A04E9302C317}']
  207.     procedure StartSuite(suite: ITest);
  208.     procedure EndSuite(suite: ITest);
  209.   end;
  210.   // a named collection of tests
  211.   ITestSuite = interface(ITest)
  212.     ['{C20E38EF-7369-44D9-9D84-08E84EC1DCF0}']
  213.     procedure AddTest(test: ITest);
  214.     procedure AddSuite(suite : ITestSuite);
  215.   end;
  216.   {  Adapter to allow a TTestResult to receive status messages
  217.      from the running test }
  218.   TStatusToResultAdapter = class(TInterfacedObject, IStatusListener)
  219.   protected
  220.     FTestResult :TTestResult;
  221.   public
  222.     constructor Create(TestResult :TTestResult);
  223.     procedure   Status(Test :ITest; const Msg :string);
  224.   end;
  225.   { A TTestResult collects the results of executing a test case.
  226.   And notifies registered ITestListener of testing events. }
  227.   TTestResult = class(TObject)
  228.   private
  229.     FTotalTime: Int64;
  230.   protected
  231.     FFailures: TList;
  232.     FErrors: TList;
  233.     FOverRides: Integer;
  234.     FListeners: IInterfaceList;
  235.     FRootTest: ITest;
  236.     FRunTests: integer;
  237.     FStop: Boolean;
  238.     FBreakOnFailures :Boolean;
  239.     FFailsIfNoChecksExecuted: Boolean;
  240.     FIgnoresMemoryLeakInSetUpTearDown: Boolean;
  241.     FMemoryLeakIgnoredInSetupOrTearDown: boolean;
  242.     FFailsIfMemoryLeaked: Boolean;
  243.     FMethodPtr: Pointer;
  244.     FStatusAdapter :IStatusListener;
  245.     procedure Run(test: ITest); virtual;
  246.     function  RunTestSetup(test: ITest):Boolean; virtual;
  247.     procedure RunTestTearDown(test: ITest); virtual;
  248.     function  RunTestRun(test: ITest) : Boolean; virtual;
  249.     procedure TestingStarts;                           virtual;
  250.     procedure StartSuite(suite: ITest);                virtual;
  251.     procedure StartTest(test: ITest);                  virtual;
  252.     function  ShouldRunTest(test :ITest) :Boolean;     virtual;
  253.     procedure Status(test :ITest; const Msg :string);  virtual;
  254.     procedure EndSuite(suite: ITest);                  virtual;
  255.     procedure EndTest(test: ITest);                    virtual;
  256.     procedure TestingEnds;                             virtual;
  257.   public
  258.     constructor Create;
  259.     destructor  Destroy; override;
  260.     procedure AddListener(listener: ITestListener); virtual;
  261.     procedure RunSuite(test: ITest);  overload;
  262.     procedure AddSuccess(test: ITest); virtual;
  263.     function  AddFailure(test: ITest; e: Exception; Addrs :Pointer): TTestFailure; overload;
  264.     function  AddFailure(test: ITest; Addrs :Pointer; msg :string = ''): TTestFailure; overload;
  265.     function  AddError(test: ITest; e: Exception; Addrs :Pointer; msg :string = ''): TTestFailure; virtual;
  266.     procedure Stop; virtual;
  267.     function  ShouldStop: Boolean; virtual;
  268.     function RunCount: integer;     virtual;
  269.     function ErrorCount: integer;   virtual;
  270.     function FailureCount: integer; virtual;
  271.     function  GetError(idx :Integer) :TTestFailure;
  272.     function  GetFailure(idx :Integer) :TTestFailure;
  273.     function  WasStopped :Boolean; virtual;
  274.     function  WasSuccessful: Boolean; virtual;
  275.     property  BreakOnFailures :Boolean read  FBreakOnFailures write FBreakOnFailures;
  276.     property  FailsIfNoChecksExecuted :Boolean read  fFailsIfNoChecksExecuted
  277.                                                write fFailsIfNoChecksExecuted;
  278.     property  FailsIfMemoryLeaked :Boolean read  fFailsIfMemoryLeaked
  279.                                            write fFailsIfMemoryLeaked;
  280.     property  IgnoresMemoryLeakInSetUpTearDown: Boolean
  281.                 read FIgnoresMemoryLeakInSetUpTearDown
  282.                 write FIgnoresMemoryLeakInSetUpTearDown;
  283.     property  MemoryLeakIgnoredInSetupOrTearDown: Boolean
  284.                 read FMemoryLeakIgnoredInSetupOrTearDown
  285.                 write FMemoryLeakIgnoredInSetupOrTearDown;
  286.     property  TotalTime: Int64 read FTotalTime;
  287.     property Errors[i :Integer] :TTestFailure read GetError;
  288.     property Failures[i :Integer] :TTestFailure read GetFailure;
  289.     property OverRides: integer read FOverRides write FOverRides;
  290.   end;
  291.   TAbstractTest = class(TInterfacedObject, ITest)
  292.   protected
  293.     FTestName: string;
  294.     FEnabled: Boolean;
  295.     FStartTime: Int64;
  296.     FStopTime:  Int64;
  297.     FStatusListener :IStatusListener;
  298.     FStatusStrings  :TStrings;
  299.     FExpectedException: ExceptionClass;
  300.     FCheckCalled: Boolean;
  301.     FFailsOnNoChecksExecuted: Boolean;
  302.     FFailsOnMemoryLeak: Boolean;
  303.     FTestMethodInvoked: Boolean;
  304.     FFailsOnMemoryRecovery: Boolean;
  305.     FIgnoreSetUpTearDownLeaks: Boolean;
  306.     FMemoryLeakIgnoredInSetupTearDown: boolean;
  307.     FAllowedLeakList: TAllowedLeakArray;
  308.     FAllowedLeakListIndex: Word;
  309.     // Object used by the GUI to map the test onto a GUI object such as a tree node
  310.     FGUIObject: TObject;
  311.     procedure Invoke(AMethod: TTestMethod); virtual;
  312.     procedure RunWithFixture(testResult: TTestResult); virtual;
  313.     procedure RunTest(testResult: TTestResult); virtual;
  314.     procedure SetUp; virtual;
  315.     procedure TearDown; virtual;
  316.     procedure SetStartTime(Value :Int64); virtual;
  317.     function  GetStartTime : Int64;       virtual;
  318.     procedure SetStopTime(Value :Int64);  virtual;
  319.     function  GetStopTime : Int64;        virtual;
  320.     procedure SetGUIObject(const guiObject: TObject);
  321.     function  GetGUIObject: TObject;
  322.     procedure SetFailsOnNoChecksExecuted(const Value: Boolean);
  323.     function  GetFailsOnNoChecksExecuted: Boolean;
  324.     function  GetFailsOnMemoryLeak: Boolean;
  325.     procedure SetFailsOnMemoryLeak(const Value: Boolean);
  326.     {$IFNDEF CLR} // related to Check(Not)EqualsMem, pointer based, unsuitable for .NET
  327.     function GetMemDiffStr(expected, actual: pointer; size:longword; msg:string):string;
  328.     {$ENDIF}
  329.     function  GetAllowedMemoryLeakSize: Integer;
  330.     procedure SetAllowedMemoryLeakSize(const NewSize: Integer);
  331.     function  GetFailsOnMemoryRecovery: Boolean;
  332.     procedure SetFailsOnMemoryRecovery(const Value: Boolean);
  333.     function  GetIgnoreSetUpTearDownLeaks: Boolean;
  334.     procedure SetIgnoreSetUpTearDownLeaks(const Value: Boolean);
  335.     function  GetMemoryLeakIgnoredInSetupTearDown: Boolean;
  336.     procedure SetMemoryLeakIgnoredInSetupTearDown(const Value: Boolean);
  337.     procedure SetAllowedLeakArray(AllowedList: array of Integer);
  338.     function  GetAllowedLeak: Integer; // Is the iterator returned below
  339.     function  GetAllowedLeaksIterator: TListIterator;
  340.   public
  341.     constructor Create(AName: string);
  342.     destructor Destroy; override;
  343.     function  GetName: string; virtual;
  344.     function  GetEnabled: Boolean; virtual;
  345.     procedure SetEnabled(value: Boolean); virtual;
  346.     function  Tests: IInterfaceList; virtual;
  347.     function  CountTestCases: integer; virtual;
  348.     function  CountEnabledTestCases: integer; virtual;
  349.     function  Run: TTestResult; overload;
  350.     procedure Run(testResult: TTestResult); overload;
  351.     function  GetTestMethodInvoked: Boolean;
  352.     procedure SetTestMethodInvoked(const Value: Boolean);
  353.     function  ElapsedTestTime: Cardinal; virtual;
  354.     procedure SetStatusListener(Listener :IStatusListener);
  355.     procedure Status(const Msg :string);
  356.     function  GetStatus :string;
  357.     procedure LoadConfiguration(const fileName: string; const useRegistry, useMemIni: Boolean); overload;
  358.     procedure LoadConfiguration(const iniFile :TCustomIniFile; const section :string);  overload; virtual;
  359.     procedure SaveConfiguration(const fileName: string; const useRegistry, useMemIni: Boolean); overload;
  360.     procedure SaveConfiguration(const iniFile :TCustomIniFile; const section :string);  overload; virtual;
  361.     property Name:    string  read GetName;
  362.     property Enabled: Boolean read GetEnabled write SetEnabled;
  363.     function  BoolToStr(ABool: Boolean): string;
  364.     procedure Check(condition: Boolean; msg: string = ''); virtual;
  365.     procedure CheckTrue(condition: Boolean; msg: string = ''); virtual;
  366.     procedure CheckFalse(condition: Boolean; msg: string = ''); virtual;
  367.     procedure CheckEquals(expected, actual: extended; msg: string = ''); overload; virtual;
  368.     procedure CheckEquals(expected, actual: extended; delta: extended; msg: string = ''); overload; virtual;
  369.     procedure CheckEquals(expected, actual: integer; msg: string = ''); overload; virtual;
  370.     procedure CheckEquals(expected, actual: string; msg: string = ''); overload; virtual;
  371.     procedure CheckEqualsString(expected, actual: string; msg: string = ''); virtual;
  372. {$IFNDEF CLR}
  373.     procedure CheckEquals(expected, actual: WideString; msg: string = ''); overload; virtual;
  374.     procedure CheckEqualsWideString(expected, actual: WideString; msg: string = ''); virtual;
  375.     procedure CheckEqualsMem(expected, actual: pointer; size:longword; msg:string=''); virtual;
  376. {$ENDIF}
  377.     procedure CheckEquals(expected, actual: Boolean; msg: string = ''); overload; virtual;
  378.     procedure CheckEqualsBin(expected, actual: longword; msg: string = ''; digits: integer=32); virtual;
  379.     procedure CheckEqualsHex(expected, actual: longword; msg: string = ''; digits: integer=8); virtual;
  380.     procedure CheckNotEquals(expected, actual: integer; msg: string = ''); overload; virtual;
  381.     procedure CheckNotEquals(expected: extended; actual: extended; delta: extended = 0; msg: string = ''); overload; virtual;
  382.     procedure CheckNotEquals(expected, actual: string; msg: string = ''); overload; virtual;
  383.     procedure CheckNotEqualsString(expected, actual: string; msg: string = ''); virtual;
  384. {$IFNDEF CLR}
  385.     procedure CheckNotEquals(const expected, actual: WideString; msg: string = ''); overload; virtual;
  386.     procedure CheckNotEqualsWideString(const expected, actual: WideString; msg: string = ''); virtual;
  387.     procedure CheckNotEqualsMem(expected, actual: pointer; size:longword; msg:string=''); virtual;
  388. {$ENDIF}
  389.     procedure CheckNotEquals(expected, actual: Boolean; msg: string = ''); overload; virtual;
  390.     procedure CheckNotEqualsBin(expected, actual: longword; msg: string = ''; digits: integer=32); virtual;
  391.     procedure CheckNotEqualsHex(expected, actual: longword; msg: string = ''; digits: integer=8); virtual;
  392.     procedure CheckNotNull(obj :IUnknown; msg :string = ''); overload; virtual;
  393.     procedure CheckNull(obj: IUnknown; msg: string = ''); overload; virtual;
  394.     procedure CheckSame(expected, actual: IUnknown; msg: string = ''); overload; virtual;
  395.     procedure CheckSame(expected, actual: TObject; msg: string = ''); overload; virtual;
  396.     procedure CheckNotNull(obj: TObject; msg: string = ''); overload; virtual;
  397.     procedure CheckNull(obj: TObject; msg: string = ''); overload; virtual;
  398.     procedure CheckException(AMethod: TTestMethod; AExceptionClass: TClass; msg :string = '');
  399.     procedure CheckEquals(  expected, actual: TClass; msg: string = ''); overload; virtual;
  400.     procedure CheckInherits(expected, actual: TClass; msg: string = ''); overload; virtual;
  401.     procedure CheckIs(AObject :TObject; AClass: TClass; msg: string = ''); overload; virtual;
  402.     procedure Fail(msg: sTring; ErrorAddrs: Pointer = nil); overload; virtual;
  403.     procedure FailEquals(expected, actual: WideString; msg: string = ''; ErrorAddrs: Pointer = nil); virtual;
  404.     procedure FailNotEquals(expected, actual: WideString; msg: string = ''; ErrorAddrs: Pointer = nil); virtual;
  405.     procedure FailNotSame(expected, actual: WideString; msg: string = ''; ErrorAddrs: Pointer = nil); virtual;
  406.     function EqualsErrorMessage(expected, actual :WideString; msg: string): WideString;
  407.     function NotEqualsErrorMessage(expected, actual :WideString; msg: string): WideString;
  408.     function NotSameErrorMessage(expected, actual, msg: string): WideString;
  409.     procedure StopTests(msg: string = ''); virtual;
  410. {$IFNDEF CLR}
  411.     procedure CheckMethodIsNotEmpty(MethodPointer: pointer);
  412. {$ENDIF}
  413.     procedure StartExpectingException(e: ExceptionClass);
  414.     procedure StopExpectingException(msg :string = '');
  415.     property ExpectedException :ExceptionClass
  416.       read  fExpectedException
  417.       write StartExpectingException;
  418.   published
  419.     property FailsOnNoChecksExecuted: Boolean
  420.       read GetFailsOnNoChecksExecuted
  421.       write SetFailsOnNoChecksExecuted;
  422.     property FailsOnMemoryLeak: Boolean
  423.       read GetFailsOnMemoryLeak
  424.       write SetFailsOnMemoryLeak;
  425.     property TestMethodInvoked: Boolean
  426.       read GetTestMethodInvoked
  427.       write SetTestMethodInvoked;
  428.     property AllowedMemoryLeakSize: Integer
  429.       read GetAllowedMemoryLeakSize
  430.       write SetAllowedMemoryLeakSize;
  431.     property AllowedLeaksIterator: TListIterator read GetAllowedLeaksIterator;
  432.     property FailsOnMemoryRecovery: Boolean
  433.       read GetFailsOnMemoryRecovery
  434.       write SetFailsOnMemoryRecovery;
  435.     property IgnoreSetUpTearDownLeaks: Boolean
  436.       read GetIgnoreSetUpTearDownLeaks
  437.       write SetIgnoreSetUpTearDownLeaks;
  438.   end;
  439.   TTestCase = class(TAbstractTest, ITest)
  440.   protected
  441.     fMethod:    TTestMethod;
  442.     procedure Invoke(AMethod: TTestMethod); override;
  443.     procedure RunWithFixture(testResult: TTestResult); override;
  444.     procedure RunTest(testResult: TTestResult); override;
  445.   public
  446.     constructor Create(MethodName: string); virtual;
  447.     class function Suite: ITestSuite; virtual;
  448.     procedure Run(testResult: TTestResult); overload;
  449.   published
  450.   end;
  451.   TTestSuite = class(TAbstractTest, ITestSuite, ITest)
  452.   protected
  453.     FTests: IInterfaceList;
  454.     procedure RunTest(testResult: TTestResult); override;
  455.   public
  456.     constructor Create; overload;
  457.     constructor Create(AName: string); overload;
  458.     constructor Create(TestClass: TTestCaseClass); overload;
  459.     constructor Create(AName: string; const Tests: array of ITest); overload;
  460.     function CountTestCases: integer;         override;
  461.     function CountEnabledTestCases: integer;  override;
  462.     function Tests: IInterfaceList;                 override;
  463.     procedure AddTest(ATest: ITest);                virtual;
  464.     procedure AddTests(testClass: TTestCaseClass);  virtual;
  465.     procedure AddSuite(suite:  ITestSuite);         virtual;
  466.     procedure LoadConfiguration(const iniFile: TCustomIniFile; const section: string);  override;
  467.     procedure SaveConfiguration(const iniFile: TCustomIniFile; const section: string);  override;
  468.   end;
  469.   TTestFailure = class(TObject)
  470.   protected
  471.     FFailedTest: ITest;
  472.     FThrownExceptionClass: TClass;
  473.     FThrownExceptionMessage: string;
  474.     FThrownExceptionAddress: Pointer;
  475.     FStackTrace:             string;
  476.     procedure CaptureStackTrace;
  477.   public
  478.     constructor Create(FailedTest: ITest; thrownException: Exception; Addrs: Pointer; msg: string = ''); overload;
  479.     constructor Create(FailedTest: ITest; Addrs: Pointer; msg: string); overload;
  480.     function FailedTest: ITest; virtual;
  481.     function ThrownExceptionClass: TClass; virtual;
  482.     function ThrownExceptionName: string; virtual;
  483.     function ThrownExceptionMessage: string; virtual;
  484.     function ThrownExceptionAddress: pointer; virtual;
  485.     function LocationInfo: string; virtual;
  486.     function AddressInfo:  string; virtual;
  487.     function StackTrace:   string; virtual;
  488.   end;
  489.   TMethodEnumerator = class
  490.   protected
  491.     FMethodNameList:  array of string;
  492.     function GetNameOfMethod(idx: integer):  string;
  493.     function GetMethodCount: Integer;
  494.   public
  495.     constructor Create(AClass: TClass);
  496.     property MethodCount: integer read GetMethodCount;
  497.     property NameOfMethod[idx:  integer]: string read GetNameOfMethod;
  498.   end;
  499. // creating suites
  500. function  TestSuite(AName: string; const Tests: array of ITest): ITestSuite;
  501. // test registry
  502. procedure RegisterTest(SuitePath: string; test: ITest); overload;
  503. procedure RegisterTest(test: ITest);                    overload;
  504. procedure RegisterTests(SuitePath: string; const Tests: array of ITest);  overload;
  505. procedure RegisterTests(const Tests: array of ITest);                     overload;
  506. function  RegisteredTests: ITestSuite;
  507. procedure ClearRegistry;
  508. // running tests
  509. function RunTest(suite: ITest; listeners: array of ITestListener): TTestResult; overload;
  510. function RunRegisteredTests(listeners: array of ITestListener): TTestResult;
  511. // utility routines
  512. function CallerAddr: Pointer; {$IFNDEF CLR} assembler; {$ENDIF}
  513. function PtrToStr(p: Pointer): string;
  514. function PointerToLocationInfo(Addrs: Pointer): string;
  515. function PointerToAddressInfo(Addrs: Pointer):  string;
  516. function IsTestMethod(aTest: ITest): Boolean;
  517. function IsDecorator(aTest: ITest): Boolean;
  518. function GetDUnitRegistryKey: string;
  519. procedure SetDUnitRegistryKey(const NewKey: string);
  520. {$IFNDEF CLR}  // - unsuitable for .NET, pointer magic
  521. function FirstByteDiff(p1, p2: pointer; size: longword; out b1, b2: byte): integer;
  522. {$ENDIF}
  523. function MemLeakMonitor: IMemLeakMonitor;
  524. //  strings, used in TAbstractTestCase.EqualsErrorMessage etc.:
  525. const sExpButWasFmt    = '%sexpected: <%s> but was: <%s>';
  526.       sExpAndActualFmt = '%sexpected and actual were: <%s>';
  527. {$UNDEF DETECTMEMLEAKS}
  528. {$IFDEF VER180}
  529.   {$IFNDEF CLR}
  530.     {$DEFINE DETECTMEMLEAKS}
  531.   {$ENDIF}
  532. {$ENDIF}
  533. {$IFDEF FASTMM}
  534.   {$DEFINE DETECTMEMLEAKS}
  535. {$ENDIF}
  536. ///////////////////////////////////////////////////////////////////////////
  537. implementation
  538. uses
  539. {$IFDEF LINUX}
  540.   Libc,
  541. {$ELSE}
  542.   Windows,
  543.   Registry,
  544. {$ENDIF}
  545. {$IFDEF USE_JEDI_JCL}
  546.   JclDebug,
  547. {$ENDIF}
  548. {$IFDEF DETECTMEMLEAKS}
  549.   FastMMMemLeakMonitor,
  550. {$ENDIF}
  551. {$IFDEF madExcept}
  552.   madStackTrace,
  553. {$ENDIF}
  554.   TypInfo;
  555. {$STACKFRAMES ON} // Required to retrieve caller's address
  556. {$IFNDEF DETECTMEMLEAKS}
  557. // Stub code for use when Memory Leak detection is disabled.
  558. // See FastMM MemLeakMonitor.pas notes for invoking memory leak detection.
  559. type
  560.   TMemLeakMonitor = class(TInterfacedObject, IMemLeakMonitor)
  561.   private
  562.     function MemLeakDetected(out LeakSize: Integer): Boolean; overload;
  563.   end;
  564. { TMemMonitor }
  565. function TMemLeakMonitor.MemLeakDetected(out LeakSize: Integer): Boolean;
  566. begin
  567.   LeakSize := 0;
  568.   Result := False;
  569. end;
  570. type
  571.   TDUnitMemLeakMonitor = class(TMemLeakMonitor, IDUnitMemLeakMonitor)
  572.     function MemLeakDetected(const AllowedLeakSize: Integer;
  573.                              const FailOnMemoryRecovery: Boolean;
  574.                              out   LeakSize: Integer): Boolean; overload;
  575.     function MemLeakDetected(const AllowedValuesGetter: TListIterator;
  576.                              const FailOnMemoryRecovery: Boolean;
  577.                              out   LeakIndex: integer;
  578.                              out   LeakSize: Integer): Boolean; overload;
  579.     function GetMemoryUseMsg(const FailOnMemoryRecovery: Boolean;
  580.                              const TestProcChangedMem: Integer;
  581.                              out   ErrorMsg: string): Boolean; overload;
  582.     function GetMemoryUseMsg(const FailOnMemoryRecovery: boolean;
  583.                              const TestSetupChangedMem: Integer;
  584.                              const TestProcChangedMem: Integer;
  585.                              const TestTearDownChangedMem: Integer;
  586.                              const TestCaseChangedMem: Integer;
  587.                              out   ErrorMsg: string): boolean; overload;
  588.     procedure MarkMemInUse;
  589.   end;
  590. { TDUnitMemMonitor }
  591. procedure TDUnitMemLeakMonitor.MarkMemInUse;
  592. begin
  593. // Do Nothing
  594. end;
  595. function TDUnitMemLeakMonitor.MemLeakDetected(const AllowedLeakSize: Integer;
  596.                                               const FailOnMemoryRecovery: Boolean;
  597.                                               out   LeakSize: Integer): Boolean;
  598. begin
  599.   inherited MemLeakDetected(LeakSize);
  600.   Result := (AllowedLeakSize <> 0);
  601. end;
  602. function TDUnitMemLeakMonitor.MemLeakDetected(const AllowedValuesGetter: TListIterator;
  603.                                               const FailOnMemoryRecovery: Boolean;
  604.                                               out   LeakIndex: integer;
  605.                                               out   LeakSize: Integer): Boolean;
  606. begin
  607.   inherited MemLeakDetected(LeakSize);
  608.   LeakIndex := 0;
  609.   Result := (AllowedValuesGetter <> 0);
  610. end;
  611. function TDUnitMemLeakMonitor.GetMemoryUseMsg(const FailOnMemoryRecovery: Boolean;
  612.                                               const TestProcChangedMem: Integer;
  613.                                               out   ErrorMsg: string): Boolean;
  614. begin
  615.   ErrorMsg := '';
  616.   Result := True;
  617. end;
  618. function TDUnitMemLeakMonitor.GetMemoryUseMsg(const FailOnMemoryRecovery: boolean;
  619.                                               const TestSetupChangedMem: Integer;
  620.                                               const TestProcChangedMem: Integer;
  621.                                               const TestTearDownChangedMem: Integer;
  622.                                               const TestCaseChangedMem: Integer;
  623.                                               out   ErrorMsg: string): boolean;
  624. begin
  625.   ErrorMsg := '';
  626.   Result := True;
  627. end;
  628. {$ENDIF}
  629. function MemLeakMonitor: IMemLeakMonitor;
  630. begin
  631.   Result := TMemLeakMonitor.Create;
  632. end;
  633. type
  634.   TMemIniFileTrimmed = class(TMemIniFile)
  635.   public
  636.     // Override the read string method to trim the string for compatibility with TIniFile
  637.     function ReadString(const Section, Ident, DefaultStr: string): string; override;
  638.   end;
  639. var
  640.   // SubKey of HKEY_CURRENT_USER for storing configurations in the registry (end with )
  641.   DUnitRegistryKey: string = ''; // How about 'SoftwareDUnitTests';
  642. {$IFDEF LINUX}
  643. var
  644.   PerformanceCounterInitValue: Int64;
  645. procedure InitPerformanceCounter;
  646. var
  647.   TV : TTimeVal;
  648.   TZ : TTimeZone;
  649. begin
  650.   gettimeofday(TV, TZ);
  651.   PerformanceCounterInitValue :=
  652.     LongWord(TV.tv_sec mod (24*60*60) * 1000) + (LongWord(TV.tv_usec) div 1000);
  653. end;
  654. function QueryPerformanceCounter(var PerformanceCounter: Int64): LongBool;
  655. var
  656.   TV : TTimeVal;
  657.   TZ : TTimeZone;
  658. begin
  659.   gettimeofday(TV, TZ);
  660.   PerformanceCounter := (TV.tv_sec mod (24*60*60) * 1000) +
  661.             (TV.tv_usec div 1000);
  662.   PerformanceCounter := PerformanceCounter - PerformanceCounterInitValue;
  663.   Result := true;
  664. end;
  665. function QueryPerformanceFrequency(var Frequency: Int64): LongBool;
  666. begin
  667.   Frequency := 1000;
  668.   Result := true;
  669. end;
  670. {$ENDIF}
  671. {: Convert a pointer into its string representation }
  672. function PtrToStr(p: Pointer): string;
  673. begin
  674.    Result := Format('%p', [p])
  675. end;
  676. function IsBadPointer(P: Pointer):Boolean; {$IFNDEF CLR} register; {$ENDIF}
  677. begin
  678.   try
  679.     Result  := (p = nil)
  680. {$IFNDEF CLR}
  681.               or ((Pointer(P^) <> P) and (Pointer(P^) = P));
  682. {$ENDIF}
  683.   except
  684.     Result := true;
  685.   end
  686. end;
  687. function CallerAddr: Pointer; {$IFNDEF CLR} assembler; {$ENDIF}
  688. {$IFDEF CLR}
  689. begin
  690.   Result := nil;
  691. end;
  692. {$ELSE}
  693. const
  694.   CallerIP = $4;
  695. asm
  696.    mov   eax, ebp
  697.    call  IsBadPointer
  698.    test  eax,eax
  699.    jne   @@Error
  700.    mov   eax, [ebp].CallerIP
  701.    sub   eax, 5   // 5 bytes for call
  702.    push  eax
  703.    call  IsBadPointer
  704.    test  eax,eax
  705.    pop   eax
  706.    je    @@Finish
  707. @@Error:
  708.    xor eax, eax
  709. @@Finish:
  710. end;
  711. {$ENDIF}
  712. {$IFNDEF USE_JEDI_JCL}
  713. {$IFNDEF madExcept}
  714. function PointerToLocationInfo(Addrs: Pointer): string;
  715. begin
  716.  Result := ''
  717. end;
  718. function PointerToAddressInfo(Addrs: Pointer): string;
  719. begin
  720.  Result := '$'+PtrToStr(Addrs);
  721. end;
  722. {$ELSE}
  723. function PointerToLocationInfo(Addrs: Pointer): string;
  724. begin
  725.  Result := StackAddrToStr( Addrs );
  726. end;
  727. function PointerToAddressInfo(Addrs: Pointer): string;
  728. begin
  729.  Result := StackAddrToStr( Addrs );
  730. end;
  731. {$ENDIF}
  732. {$ELSE}
  733. function PointerToLocationInfo(Addrs: Pointer): string;
  734. var
  735.   _file,
  736.   _module,
  737.   _proc: AnsiString;
  738.   _line: integer;
  739. begin
  740.   JclDebug.MapOfAddr(Addrs, _file, _module, _proc, _line);
  741.   if _file <> '' then
  742.     Result   := Format('%s:%d', [_file, _line])
  743.   else
  744.     Result   := _module;
  745. end;
  746. function PointerToAddressInfo(Addrs: Pointer): string;
  747. var
  748.   _file,
  749.   _module,
  750.   _proc: AnsiString;
  751.   _line: integer;
  752. begin
  753.   JclDebug.MapOfAddr(Addrs, _file, _module, _proc, _line);
  754.   Result := Format('%s$%p', [_proc, Addrs]);
  755. end;
  756. {$ENDIF}
  757. function IsTestMethod(aTest: ITest): Boolean;
  758. var
  759.   aTestSuite: ITestSuite;
  760.   aTestDecorator: ITestDecorator;
  761. begin
  762.   Assert(Assigned(aTest));
  763.   // Initialize to be sure
  764.   aTestSuite := nil;
  765.   aTestDecorator := nil;
  766.   { The test should be a normal testmethod
  767.     when the testcount = 1 }
  768.   Result := (aTest.CountTestCases = 1);
  769.   // But not when the test is a suite? (It could have one test.)
  770. {$IFDEF CLR}
  771.   if Supports(aTest, ITestSuite) or Supports(aTest, ITestDecorator) then
  772.     Result := false;
  773. {$ELSE}
  774.   aTest.QueryInterface(ITestSuite, aTestSuite);
  775.   if Assigned(aTestSuite) then
  776.     Result := false;
  777.   // And not when the test is a decorator?
  778.   aTest.QueryInterface(ITestDecorator, aTestDecorator);
  779.   if Assigned(aTestDecorator) then
  780.     Result := false;
  781. {$ENDIF}
  782. end;
  783. function IsDecorator(aTest: ITest): Boolean;
  784. var
  785.   aTestDecorator: ITestDecorator;
  786. begin
  787.   Assert(Assigned(aTest));
  788.   // Initialize to be sure
  789.   aTestDecorator := nil;
  790. {$IFDEF CLR}
  791.   Result := Supports(aTest, ItestDecorator);
  792. {$ELSE}
  793.   aTest.QueryInterface(ITestDecorator, aTestDecorator);
  794.   Result := Assigned(aTestDecorator);
  795. {$ENDIF}
  796. end;
  797. function GetDUnitRegistryKey: string;
  798. begin
  799.   Result := DUnitRegistryKey;
  800. end;
  801. procedure SetDUnitRegistryKey(const NewKey: string);
  802. begin
  803.   DUnitRegistryKey := NewKey;
  804. end;
  805. {$IFNDEF CLR} // KGS: not expected to work in .NET, pointer magic follows
  806. function ByteAt(p: pointer; const Offset: integer): byte;
  807. begin
  808.   Result:=pByte(integer(p)+Offset)^;
  809. end;
  810. function FirstByteDiff(p1, p2: pointer; size: longword; out b1, b2: byte): integer;
  811. // Returns offset of first byte pair (left to right, incrementing address) that is unequal
  812. // Returns -1 if no difference found, or if size=0
  813. var
  814.   i: integer;
  815. begin
  816.   Result:=-1;
  817.   if size>0 then
  818.   for i:=0 to size-1 do // Subject to optimisation for sure:
  819.     if ByteAt(p1,i)<>ByteAt(p2,i) then
  820.     begin
  821.       Result:=i;
  822.       b1:=ByteAt(p1,i);
  823.       b2:=ByteAt(p2,i);
  824.       break;
  825.     end;
  826. end;
  827. {$ENDIF}
  828. { TTestResult }
  829. constructor TTestResult.Create;
  830. begin
  831.   inherited Create;
  832.   FFailures := TList.Create;
  833.   FErrors := TList.Create;
  834.   FListeners := TInterfaceList.Create;
  835.   FRunTests := 0;
  836.   FStop := false;
  837.   FStatusAdapter := TStatusToResultAdapter.Create(Self);
  838. end;
  839. destructor TTestResult.destroy;
  840. var
  841.   i: Integer;
  842. begin
  843.   for i := 0 to fErrors.Count - 1 do
  844.   begin
  845.     TTestFailure(fErrors[i]).Free;
  846.   end;
  847.   FErrors.Free;
  848.   for i := 0 to fFailures.Count - 1 do
  849.   begin
  850.     TTestFailure(fFailures[i]).Free;
  851.   end;
  852.   FFailures.Free;
  853.   inherited;
  854. end;
  855. procedure TTestResult.AddSuccess(test: ITest);
  856. var
  857.   i: integer;
  858. begin
  859.   assert(assigned(test));
  860.   for i := 0 to fListeners.count - 1 do
  861.   begin
  862.     (fListeners[i] as ITestListener).AddSuccess(test);
  863.   end;
  864. end;
  865. function TTestResult.AddError(test: ITest; e: Exception; Addrs: Pointer; msg: string): TTestFailure;
  866. var
  867.   i: integer;
  868.   TestFailureError:  TTestFailure;
  869. begin
  870.   assert(assigned(test));
  871.   assert(assigned(e));
  872.   assert(assigned(fErrors));
  873.   TestFailureError := TTestFailure.Create(test, e, Addrs, msg);
  874.   FErrors.add(TestFailureError);
  875.   for i := 0 to FListeners.count - 1 do
  876.   begin
  877.     (FListeners[i] as ITestListener).AddError(TestFailureError);
  878.   end;
  879.   assert(assigned(TestFailureError));
  880.   Result := TestFailureError;
  881. end;
  882. function TTestResult.AddFailure(test: ITest; e: Exception; Addrs: Pointer): TTestFailure;
  883. var
  884.   i: integer;
  885.   Failure:  TTestFailure;
  886. begin
  887.   assert(assigned(test));
  888.   assert(assigned(e));
  889.   assert(assigned(fFailures));
  890.   Failure := TTestFailure.Create(test, e, Addrs);
  891.   FFailures.add(Failure);
  892.   for i := 0 to FListeners.count - 1 do
  893.   begin
  894.     (FListeners[i] as ITestListener).AddFailure(Failure);
  895.   end;
  896.   assert(assigned(Failure));
  897.   Result := Failure;
  898. end;
  899. procedure TTestResult.addListener(listener: ITestListener);
  900. begin
  901.   assert(assigned(listener), 'listener is nil');
  902.   FListeners.add(listener);
  903. end;
  904. procedure TTestResult.EndTest(test: ITest);
  905. var
  906.   i: integer;
  907. begin
  908.   assert(assigned(FListeners));
  909.   try
  910.     for i := 0 to FListeners.count - 1 do
  911.     begin
  912.       (FListeners[i] as ITestListener).EndTest(test);
  913.     end;
  914.   finally
  915.     test.SetStatusListener(nil);
  916.   end;
  917. end;
  918. procedure TTestResult.Status(test: ITest; const Msg: string);
  919. var
  920.   i: integer;
  921. begin
  922.   assert(assigned(FListeners));
  923.   for i := 0 to FListeners.count - 1 do
  924.   begin
  925.     (FListeners[i] as ITestListener).Status(test, Msg);
  926.   end;
  927. end;
  928. function TTestResult.GetError(idx :Integer): TTestFailure;
  929. begin
  930.   Result := TObject(FErrors[idx]) as TTestFailure;
  931. end;
  932. function TTestResult.GetFailure(idx :Integer): TTestFailure;
  933. begin
  934.   Result := TObject(FFailures[idx]) as TTestFailure;
  935. end;
  936. function TTestResult.RunTestSetup(test: ITest):Boolean;
  937. var
  938.   LTime :Int64;
  939. begin
  940.   Result := false;
  941.   try
  942.     test.StopTime := 0;
  943.     QueryPerformanceCounter(LTime);
  944.     test.StartTime := LTime;
  945.     test.FailsOnNoChecksExecuted := FFailsIfNoChecksExecuted;
  946.     test.FailsOnMemoryLeak := FFailsIfMemoryLeaked;
  947.     test.IgnoreSetUpTearDownLeaks:= FIgnoresMemoryLeakInSetUpTearDown;
  948.     test.SetUp;
  949.     Result := true;
  950.   except
  951.     on e: Exception do
  952.     begin
  953.       AddError(test, e, ExceptAddr, 'SetUp FAILED: ');
  954.     end;
  955.   end;
  956. end;
  957. procedure TTestResult.RunTestTearDown(test: ITest);
  958. var
  959.   LTime :Int64;
  960. begin
  961.   try
  962.     test.TearDown;
  963.   except
  964.     on e: Exception do
  965.       AddError(test, e, ExceptAddr, 'TearDown FAILED: ');
  966.   end;
  967.   QueryPerformanceCounter(LTime);
  968.   test.StopTime := LTime;
  969. end;
  970. function TTestResult.RunTestRun(test: ITest) : Boolean;
  971. var
  972.   failure: TTestFailure;
  973. begin
  974.   Result := false;
  975.   test.TestMethodInvoked := False;
  976.   failure := nil;
  977.   {$IFDEF USE_JEDI_JCL}
  978.   try
  979.     JclStartExceptionTracking;
  980.   {$ENDIF}
  981.     try
  982.       test.RunTest(self);
  983.       if not Assigned(FRootTest) then
  984.         FRootTest := test;
  985.       FTotalTime := FRootTest.ElapsedTestTime;
  986.       Result := true;
  987.     except
  988.       on e: EStopTestsFailure do
  989.       begin
  990.         failure := AddFailure(test, e, ExceptAddr);
  991.         FStop := True;
  992.       end;
  993.       on e: ETestFailure do
  994.       begin
  995.         failure := AddFailure(test, e, ExceptAddr);
  996.       end;
  997.       on e: EBreakingTestFailure do
  998.       begin
  999.         failure := AddFailure(test, e, ExceptAddr);
  1000.       end;
  1001.       on e: Exception do
  1002.       begin
  1003.         failure := AddError(test, e, ExceptAddr);
  1004.       end;
  1005.     end;
  1006.   {$IFDEF USE_JEDI_JCL}
  1007.   finally
  1008.     JclStopExceptionTracking;
  1009.   end;
  1010.   {$ENDIF}
  1011.   if BreakOnFailures
  1012.   and (failure <> nil)
  1013.   and (failure.FThrownExceptionClass.InheritsFrom(ETestFailure))
  1014.   then
  1015.   begin
  1016.     try
  1017.        raise EBreakingTestFailure.Create(failure.ThrownExceptionMessage)
  1018.           {$IFNDEF CLR}at failure.ThrownExceptionAddress{$ENDIF};
  1019.     except
  1020.     end;
  1021.   end;
  1022. end;
  1023. procedure TTestResult.Run(test: ITest);
  1024. var
  1025.   TestProcExecuted: Boolean;
  1026.   TestCaseMemLeakMonitor : IDUnitMemLeakMonitor;
  1027.   TestProcMemLeakMonitor : IDUnitMemLeakMonitor;
  1028.   TestProcMemdiff        : Integer;
  1029.   TestCaseMemdiff        : Integer;
  1030.   TestCasePassed         : Boolean;
  1031.   ErrorMessage           : string;
  1032.   MemImbalance           : Boolean;
  1033.   SetupMemDiff           : Integer;
  1034.   TearDownMemDiff        : Integer;
  1035.   LeakIndex              : Integer;
  1036. begin
  1037.   assert(assigned(test));
  1038.   if not ShouldStop and ShouldRunTest(test) then
  1039.   begin
  1040.     StartTest(test);
  1041.     test.AllowedMemoryLeakSize := 0;
  1042.     try
  1043.       TestProcExecuted := False;
  1044.       TestCasePassed := False;
  1045.       TestCaseMemdiff := 0;
  1046.       TestProcMemdiff := 0;
  1047.       ErrorMessage := '';
  1048.       // Start monitoring memory allocation before Setup.
  1049.       TestProcMemLeakMonitor := TDUnitMemLeakMonitor.Create;
  1050.       TestCaseMemLeakMonitor := TDUnitMemLeakMonitor.Create;
  1051.       if RunTestSetUp(test) then
  1052.       begin
  1053.         // See if Setup Leaked.
  1054.         (TestCaseMemLeakMonitor as IMemLeakMonitor).MemLeakDetected(SetupMemDiff);
  1055.         TestProcMemLeakMonitor.MarkMemInUse;
  1056.         TestCasePassed := RunTestRun(test);
  1057.         //Not all calls to RunTestRun call Test Procedures so check if this was.
  1058.         TestProcExecuted := isTestMethod(test);
  1059.         if TestProcExecuted and test.FailsOnMemoryLeak then
  1060.           (TestProcMemLeakMonitor as IMemLeakMonitor).MemLeakDetected(TestProcMemdiff);
  1061.       end;
  1062.       TestProcMemLeakMonitor.MarkMemInUse;
  1063.       RunTestTearDown(test);
  1064.       (TestProcMemLeakMonitor as IMemLeakMonitor).MemLeakDetected(TearDownMemDiff);
  1065.       // Reporting of test success is delayed from within RunTestRun so mem leak
  1066.       // can be flagged as failure at testcase level encompasing all of
  1067.       // SetUp, Run and TearDown.
  1068.       if TestCasePassed then
  1069.       begin
  1070.         if not TestProcExecuted or not test.FailsOnMemoryLeak then
  1071.           // Show non Test Procedure call success or TestCase success if not
  1072.           // showing failure on memory status change
  1073.           AddSuccess(test)
  1074.         else
  1075.         begin
  1076.           MemImbalance := TestCaseMemLeakMonitor.MemLeakDetected(test.AllowedLeaksIterator,
  1077.                                                                  test.FailsOnMemoryRecovery,
  1078.                                                                  LeakIndex,
  1079.                                                                  TestCaseMemdiff);
  1080.           FMemoryLeakIgnoredInSetupOrTearDown := IgnoresMemoryLeakInSetUpTearDown and
  1081.             (TestProcMemdiff = 0) and MemImbalance;
  1082.           if not FMemoryLeakIgnoredInSetupOrTearDown and (MemImbalance and
  1083.             (not TestCaseMemLeakMonitor.GetMemoryUseMsg(test.FailsOnMemoryRecovery,
  1084.                                                         SetupMemDiff,
  1085.                                                         TestProcMemdiff,
  1086.                                                         TearDownMemDiff,
  1087.                                                         TestCaseMemdiff,
  1088.                                                         ErrorMessage))) then
  1089.             AddFailure(test, FMethodPtr, ErrorMessage)
  1090.           else
  1091.           begin
  1092.             AddSuccess(test);
  1093.             //Report back allowed leak size actually used from list of sizes
  1094.             if (TestCaseMemdiff <> 0) then
  1095.              Test.AllowedMemoryLeakSize := TestCaseMemdiff;
  1096.           end;
  1097.         end;
  1098.       end;
  1099.     finally
  1100.       EndTest(test);
  1101.       TestProcMemLeakMonitor := nil;
  1102.       TestCaseMemLeakMonitor := nil;
  1103.     end;
  1104.   end;
  1105. end;
  1106. function TTestResult.RunCount: integer;
  1107. begin
  1108.   Result := FRunTests;
  1109. end;
  1110. function TTestResult.ShouldStop: Boolean;
  1111. begin
  1112.   Result := FStop;
  1113. end;
  1114. procedure TTestResult.StartTest(test: ITest);
  1115. var
  1116.   i: integer;
  1117. begin
  1118.   assert(assigned(test));
  1119.   assert(assigned(FListeners));
  1120.   test.SetStatusListener(FStatusAdapter);
  1121.   for i := 0 to FListeners.count - 1 do
  1122.   begin
  1123.     (FListeners[i] as ITestListener).StartTest(test);
  1124.   end;
  1125. end;
  1126. procedure TTestResult.Stop;
  1127. begin
  1128.   FStop := true;
  1129. end;
  1130. function TTestResult.ErrorCount: integer;
  1131. begin
  1132.   assert(assigned(FErrors));
  1133.   Result := FErrors.count;
  1134. end;
  1135. function TTestResult.FailureCount: integer;
  1136. begin
  1137.   assert(assigned(FFailures));
  1138.   Result := FFailures.count;
  1139. end;
  1140. function TTestResult.WasSuccessful: Boolean;
  1141. begin
  1142.   Result := (FailureCount = 0) and (ErrorCount() = 0) and not WasStopped;
  1143. end;
  1144. procedure TTestResult.TestingStarts;
  1145. var
  1146.   i: Integer;
  1147. begin
  1148.   for i := 0 to FListeners.count - 1 do
  1149.   begin
  1150.     (FListeners[i] as ITestListener).TestingStarts;
  1151.   end;
  1152. end;
  1153. procedure TTestResult.TestingEnds;
  1154. var
  1155.   i: Integer;
  1156. begin
  1157.   for i := 0 to FListeners.count - 1 do
  1158.   begin
  1159.     (FListeners[i] as ITestListener).TestingEnds(self);
  1160.   end;
  1161. end;
  1162. function TTestResult.ShouldRunTest(test: ITest): Boolean;
  1163. var
  1164.   i: Integer;
  1165. begin
  1166.   Result := True;
  1167.   for i := 0 to FListeners.count - 1 do
  1168.   begin
  1169.     if not (FListeners[i] as ITestListener).ShouldRunTest(test) then
  1170.     begin
  1171.       Result := false;
  1172.       break;
  1173.     end;
  1174.   end;
  1175. end;
  1176. function TTestResult.WasStopped: Boolean;
  1177. begin
  1178.   Result := FStop;
  1179. end;
  1180. procedure TTestResult.RunSuite(test: ITest);
  1181. begin
  1182.   TestingStarts;
  1183.   try
  1184.     FRootTest := test;
  1185.     test.RunWithFixture(self);
  1186.   finally
  1187.     TestingEnds
  1188.   end
  1189. end;
  1190. procedure TTestResult.EndSuite(suite: ITest);
  1191. var
  1192.   i: Integer;
  1193.   l: ITestListenerX;
  1194. begin
  1195.   for i := 0 to FListeners.count - 1 do
  1196.   begin
  1197. {$IFDEF CLR}
  1198.     if Supports(FListeners[i], ITestListenerX, l) then
  1199. {$ELSE}
  1200.     if FListeners[i].QueryInterface(ITestListenerX, l) = 0 then
  1201. {$ENDIF}
  1202.        l.EndSuite(suite);
  1203.   end;
  1204. end;
  1205. procedure TTestResult.StartSuite(suite: ITest);
  1206. var
  1207.   i: Integer;
  1208.   l: ITestListenerX;
  1209. begin
  1210.   for i := 0 to FListeners.count - 1 do
  1211.   begin
  1212. {$IFDEF CLR}
  1213.     if Supports(FListeners[i], ITestListenerX, l) then
  1214. {$ELSE}
  1215.     if FListeners[i].QueryInterface(ITestListenerX, l) = 0 then
  1216. {$ENDIF}
  1217.       l.StartSuite(suite);
  1218.   end;
  1219. end;
  1220. function TTestResult.AddFailure(test: ITest; Addrs: Pointer; msg :string = ''): TTestFailure;
  1221. var
  1222.   i: integer;
  1223.   Failure:  TTestFailure;
  1224. begin
  1225.   assert(assigned(test));
  1226.   assert(assigned(FFailures));
  1227.   Failure := TTestFailure.Create(test, Addrs, msg);
  1228.   FFailures.add(Failure);
  1229.   for i := 0 to FListeners.count - 1 do
  1230.   begin
  1231.     (FListeners[i] as ITestListener).AddFailure(Failure);
  1232.   end;
  1233.   assert(assigned(Failure));
  1234.   Result := Failure;
  1235. end;
  1236. { TStatusToResultAdapter }
  1237. constructor TStatusToResultAdapter.Create(TestResult: TTestResult);
  1238. begin
  1239.   Assert(TestResult <> nil, 'Expected non nil TestResult');
  1240.   inherited Create;
  1241.   FTestResult := TestResult;
  1242. end;
  1243. procedure TStatusToResultAdapter.Status(Test: ITest; const Msg: string);
  1244. begin
  1245.   FTestResult.Status(Test, Msg);
  1246. end;
  1247. { TAbstractTest }
  1248. constructor TAbstractTest.Create(AName: string);
  1249. var
  1250.   I: Integer;
  1251. begin
  1252.   inherited Create;
  1253.   FTestName := AName;
  1254.   FEnabled  := true;
  1255.   for I := 0 to Length(FAllowedLeakList) - 1 do    // Iterate
  1256.     FAllowedLeakList[I] := 0;
  1257. end;
  1258. destructor TAbstractTest.Destroy;
  1259. begin
  1260.   FStatusStrings.Free;
  1261.   FStatusListener := nil;
  1262.   inherited;
  1263. end;
  1264. procedure TAbstractTest.Invoke(AMethod: TTestMethod);
  1265. begin
  1266.   FTestMethodInvoked := False;
  1267. end;
  1268. procedure TAbstractTest.Run(testResult: TTestResult);
  1269. begin
  1270.   FailsOnNoChecksExecuted := testResult.FailsIfNoChecksExecuted;
  1271.   FailsOnMemoryLeak := testResult.FailsIfMemoryLeaked;
  1272.   IgnoreSetUpTearDownLeaks := testResult.IgnoresMemoryLeakInSetUpTearDown;
  1273.   testResult.RunSuite(self);
  1274. end;
  1275. function TAbstractTest.CountEnabledTestCases: integer;
  1276. begin
  1277.   if GetEnabled then
  1278.     Result := 1
  1279.   else
  1280.     Result := 0
  1281. end;
  1282. function TAbstractTest.CountTestCases: integer;
  1283. begin
  1284.   Result := 1;
  1285. end;
  1286. function TAbstractTest.getEnabled: Boolean;
  1287. begin
  1288.   Result := FEnabled
  1289. end;
  1290. function TAbstractTest.GetName: string;
  1291. begin
  1292.   Result := FTestName
  1293. end;
  1294. procedure TAbstractTest.LoadConfiguration(const fileName: string; const useRegistry, useMemIni: Boolean);
  1295. var
  1296.   f: TCustomIniFile;
  1297. begin
  1298. {$IFNDEF LINUX}
  1299.   if useRegistry then
  1300.     f := TRegistryIniFile.Create(DUnitRegistryKey + fileName)
  1301.   else
  1302. {$ENDIF}
  1303.     if useMemIni then
  1304.       f := TMemIniFileTrimmed.Create(fileName)
  1305.     else
  1306.       f := TIniFile.Create(fileName);
  1307.   try
  1308.     LoadConfiguration(f, 'Tests')
  1309.   finally
  1310.     f.free
  1311.   end
  1312. end;
  1313. procedure TAbstractTest.LoadConfiguration(const iniFile: TCustomIniFile; const section: string);
  1314. begin
  1315.   self.setEnabled(iniFile.readBool(section, self.GetName, True));
  1316. end;
  1317. procedure TAbstractTest.SaveConfiguration(const fileName: string; const useRegistry, useMemIni: Boolean);
  1318. var
  1319.   f: TCustomIniFile;
  1320. begin
  1321. {$IFNDEF LINUX}
  1322.   if useRegistry then
  1323.     f := TRegistryIniFile.Create(DUnitRegistryKey + fileName)
  1324.   else
  1325. {$ENDIF}
  1326.     if useMemIni then
  1327.       f := TMemIniFileTrimmed.Create(fileName)
  1328.     else
  1329.       f := TIniFile.Create(fileName);
  1330.   try
  1331.     SaveConfiguration(f, 'Tests');
  1332.     f.UpdateFile;
  1333.   finally
  1334.     f.free
  1335.   end
  1336. end;
  1337. procedure TAbstractTest.SaveConfiguration(const iniFile: TCustomIniFile; const section: string);
  1338. begin
  1339.   if self.GetEnabled then
  1340.     iniFile.deleteKey(section, self.GetName)
  1341.   else
  1342.     iniFile.writeBool(section, self.GetName, False);
  1343. end;
  1344. function TAbstractTest.Run: TTestResult;
  1345. var
  1346.   testResult:  TTestResult;
  1347. begin
  1348.   testResult := TTestResult.Create;
  1349.   try
  1350.     testResult.FailsIfNoChecksExecuted := self.FailsOnNoChecksExecuted;
  1351.     testResult.FailsIfMemoryLeaked := self.FailsOnMemoryLeak;
  1352.     testResult.IgnoresMemoryLeakInSetUpTearDown := IgnoreSetUpTearDownLeaks;
  1353.     testResult.RunSuite(self);
  1354.   except
  1355.     testResult.Free;
  1356.     raise;
  1357.   end;
  1358.   Result := testResult;
  1359. end;
  1360. procedure TAbstractTest.setEnabled(value: Boolean);
  1361. begin
  1362.   FEnabled := value;
  1363. end;
  1364. var
  1365.   EmptyTestList: IInterfaceList = nil;
  1366. function TAbstractTest.Tests: IInterfaceList;
  1367. begin
  1368.    if EmptyTestList = nil then
  1369.      EmptyTestList := TInterfaceList.Create;
  1370.    Result := EmptyTestList;
  1371. end;
  1372. function TAbstractTest.GetStartTime: Int64;
  1373. begin
  1374.   Result := FStartTime
  1375. end;
  1376. procedure TAbstractTest.SetStartTime(Value: Int64);
  1377. begin
  1378.   FStartTime := Value;
  1379. end;
  1380. procedure TAbstractTest.SetStopTime(Value: Int64);
  1381. begin
  1382.   FStopTime := Value;
  1383. end;
  1384. function TAbstractTest.GetStopTime: Int64;
  1385. begin
  1386.   Result := FStopTime;
  1387. end;
  1388. procedure TAbstractTest.SetUp;
  1389. begin
  1390.  // do nothing
  1391. end;
  1392. procedure TAbstractTest.TearDown;
  1393. begin
  1394.   // do nothing
  1395. end;
  1396. procedure TAbstractTest.RunTest(testResult: TTestResult);
  1397. begin
  1398.   // do nothing
  1399. end;
  1400. function TAbstractTest.ElapsedTestTime: Cardinal;
  1401. var
  1402.   Freq, LTime: Int64;
  1403. begin
  1404.   // returns TestTime in millisecs
  1405.   if fStopTime > 0 then
  1406.     LTime := FStopTime
  1407.   else if FStartTime > 0 then
  1408.     QueryPerformanceCounter(LTime)
  1409.   else
  1410.     LTime := 0;
  1411.   LTime := LTime - FStartTime;
  1412.   if QueryPerformanceFrequency(Freq) then
  1413.     Result := (1000*LTime) div Freq
  1414.   else
  1415.     Result := 0;
  1416. end;
  1417. procedure TAbstractTest.SetStatusListener(Listener: IStatusListener);
  1418. begin
  1419.   FStatusListener := Listener;
  1420. end;
  1421. function TAbstractTest.GetStatus: string;
  1422. begin
  1423.   if FStatusStrings = nil then
  1424.     Result := ''
  1425.   else
  1426.     Result := FStatusStrings.Text;
  1427. end;
  1428. procedure TAbstractTest.Status(const Msg: string);
  1429. begin
  1430.   if FStatusStrings = nil then
  1431.     FStatusStrings := TStringList.Create;
  1432.   FStatusStrings.Add(Msg);
  1433.   if FStatusListener <> nil then
  1434.     FStatusListener.Status(self, Msg);
  1435. end;
  1436. procedure TAbstractTest.RunWithFixture(testResult: TTestResult);
  1437. begin
  1438.   assert(assigned(testResult));
  1439.   if testResult.ShouldRunTest(self) then
  1440.     testResult.Run(self);
  1441. end;
  1442. procedure TAbstractTest.Check(condition: Boolean; msg: string);
  1443. begin
  1444.   FCheckCalled := True;
  1445.     if (not condition) then
  1446.         Fail(msg, CallerAddr);
  1447. end;
  1448. procedure TAbstractTest.CheckTrue(condition: Boolean; msg: string);
  1449. begin
  1450.   FCheckCalled := True;
  1451.   if (not condition) then
  1452.       FailNotEquals(BoolToStr(true), BoolToStr(false), msg, CallerAddr);
  1453. end;
  1454. procedure TAbstractTest.CheckFalse(condition: Boolean; msg: string);
  1455. begin
  1456.   FCheckCalled := True;
  1457.   if (condition) then
  1458.       FailNotEquals(BoolToStr(false), BoolToStr(true), msg, CallerAddr);
  1459. end;
  1460. procedure TAbstractTest.Fail(msg: string; ErrorAddrs: Pointer = nil);
  1461. begin
  1462. {$IFDEF CLR}
  1463.   raise ETestFailure.Create(msg);
  1464. {$ELSE}
  1465.   if ErrorAddrs = nil then
  1466.     raise ETestFailure.Create(msg) at CallerAddr
  1467.   else
  1468.     raise ETestFailure.Create(msg) at ErrorAddrs;
  1469. {$ENDIF}
  1470. end;
  1471. procedure TAbstractTest.StopTests(msg: string);
  1472. begin
  1473.   raise EStopTestsFailure.Create(msg);
  1474. end;
  1475. procedure TAbstractTest.FailNotEquals( expected,
  1476.                                        actual   : WideString;
  1477.                                        msg      : string = '';
  1478.                                        ErrorAddrs: Pointer = nil);
  1479. begin
  1480.     Fail(notEqualsErrorMessage(expected, actual, msg), ErrorAddrs);
  1481. end;
  1482. procedure TAbstractTest.FailEquals(       expected,
  1483.                                           actual   : WideString;
  1484.                                           msg      : string = '';
  1485.                                           ErrorAddrs: Pointer = nil);
  1486. begin
  1487.     Fail(EqualsErrorMessage(expected, actual, msg), ErrorAddrs);
  1488. end;
  1489. procedure TAbstractTest.FailNotSame( expected,
  1490.                                      actual   : WideString;
  1491.                                      msg      : string = '';
  1492.                                      ErrorAddrs: Pointer = nil);
  1493. begin
  1494.     Fail(NotSameErrorMessage(expected, actual, msg), ErrorAddrs);
  1495. end;
  1496. procedure TAbstractTest.CheckEquals( expected,
  1497.                                      actual   : extended;
  1498.                                      delta    : extended;
  1499.                                      msg      : string = '');
  1500. begin
  1501.   FCheckCalled := True;
  1502.     if (abs(expected-actual) > delta) then
  1503.         FailNotEquals(FloatToStr(expected), FloatToStr(actual), msg, CallerAddr);
  1504. end;
  1505. procedure TAbstractTest.CheckEquals(expected, actual: extended; msg: string);
  1506. begin
  1507.   CheckEquals(expected, actual, 0, msg);
  1508. end;
  1509. procedure TAbstractTest.CheckNotNull(obj: IUnknown; msg: string);
  1510. begin
  1511.   FCheckCalled := True;
  1512.     if obj = nil then
  1513.       Fail(msg, CallerAddr);
  1514. end;
  1515. procedure TAbstractTest.CheckNull(obj: IUnknown; msg: string);
  1516. begin
  1517.   FCheckCalled := True;
  1518.     if obj <>  nil then
  1519.       Fail(msg, CallerAddr);
  1520. end;
  1521. procedure TAbstractTest.CheckSame(expected, actual: IUnknown; msg: string = '');
  1522. begin
  1523.   FCheckCalled := True;
  1524.     if (expected <> actual) then
  1525.       FailNotSame(PtrToStr(Pointer(expected)), PtrToStr(Pointer(actual)), msg, CallerAddr);
  1526. end;
  1527. procedure TAbstractTest.CheckEquals(expected, actual: string; msg: string = '');
  1528. begin
  1529.   FCheckCalled := True;
  1530.   if expected <> actual then
  1531.     FailNotEquals(expected, actual, msg, CallerAddr);
  1532. end;
  1533. procedure TAbstractTest.CheckEqualsString(expected, actual: string; msg: string = '');
  1534. begin
  1535.   FCheckCalled := True;
  1536.   if expected <> actual then
  1537.     FailNotEquals(expected, actual, msg, CallerAddr);
  1538. end;
  1539. {$IFNDEF CLR}
  1540. procedure TAbstractTest.CheckEquals(expected, actual: WideString; msg: string = '');
  1541. begin
  1542.   FCheckCalled := True;
  1543.   if expected <> actual then
  1544.     FailNotEquals(expected, actual, msg, CallerAddr);
  1545. end;
  1546. procedure TAbstractTest.CheckEqualsWideString(expected, actual: WideString; msg: string = '');
  1547. begin
  1548.   FCheckCalled := True;
  1549.   if expected <> actual then
  1550.     FailNotEquals(expected, actual, msg, CallerAddr);
  1551. end;
  1552. function TAbstractTest.GetMemDiffStr(expected, actual: pointer; size:longword; msg:string):string;
  1553. var
  1554.   db1, db2: byte;
  1555.   Offset: integer;
  1556. begin
  1557.   Offset:=FirstByteDiff(expected,actual,size,db1,db2);
  1558.   Result:=NotEqualsErrorMessage(IntToHex(db1,2),IntToHex(db2,2),msg);
  1559.   Result:=Result+' at Offset = '+IntToHex(Offset,4)+'h';
  1560. end;
  1561. procedure TAbstractTest.CheckEqualsMem(expected, actual: pointer; size:longword; msg:string='');
  1562. begin
  1563.   FCheckCalled := True;
  1564.   if not CompareMem(expected, actual, size) then
  1565.     Fail(GetMemDiffStr(expected, actual, size, msg), CallerAddr);
  1566. end;
  1567. {$ENDIF}
  1568. procedure TAbstractTest.CheckNotEquals(expected, actual: string; msg: string = '');
  1569. begin
  1570.   FCheckCalled := True;
  1571.   if expected = actual then
  1572.     FailEquals(expected, actual, msg, CallerAddr);
  1573. end;
  1574. procedure TAbstractTest.CheckNotEqualsString(expected, actual: string; msg: string = '');
  1575. begin
  1576.   FCheckCalled := True;
  1577.   if expected = actual then
  1578.     FailEquals(expected, actual, msg, CallerAddr);
  1579. end;
  1580. {$IFNDEF CLR}
  1581. procedure TAbstractTest.CheckNotEquals(const expected, actual: WideString; msg: string = '');
  1582. begin
  1583.   FCheckCalled := True;
  1584.   if expected = actual then
  1585.     FailEquals(expected, actual, msg, CallerAddr);
  1586. end;
  1587. procedure TAbstractTest.CheckNotEqualsWideString(const expected, actual: WideString; msg: string = '');
  1588. begin
  1589.   FCheckCalled := True;
  1590.   if expected = actual then
  1591.     FailEquals(expected, actual, msg, CallerAddr);
  1592. end;
  1593. // Expected not to work under CLR (pointer based) - KGS
  1594. procedure TAbstractTest.CheckNotEqualsMem(expected, actual: pointer; size:longword; msg:string='');
  1595. begin
  1596.   FCheckCalled := True;
  1597.   if CompareMem(expected, actual, size) then
  1598.   begin
  1599.     if msg <>'' then msg := msg + ', ';
  1600.     Fail(msg+'Memory content was identical', CallerAddr);
  1601.   end;
  1602. end;
  1603. {$ENDIF}
  1604. procedure TAbstractTest.CheckEquals(expected, actual: integer; msg: string);
  1605. begin
  1606.   FCheckCalled := True;
  1607.   if (expected <> actual) then
  1608.     FailNotEquals(IntToStr(expected), IntToStr(actual), msg, CallerAddr);
  1609. end;
  1610. procedure TAbstractTest.CheckNotEquals(expected, actual: integer; msg: string = '');
  1611. begin
  1612.   FCheckCalled := True;
  1613.   if expected = actual then
  1614.     FailEquals(IntToStr(expected), IntToStr(actual), msg, CallerAddr);
  1615. end;
  1616. procedure TAbstractTest.CheckNotEquals(expected: extended; actual: extended; delta: extended = 0; msg: string = '');
  1617. begin
  1618.   FCheckCalled := True;
  1619.     if (abs(expected-actual) <= delta) then
  1620.         FailNotEquals(FloatToStr(expected), FloatToStr(actual), msg, CallerAddr);
  1621. end;
  1622. procedure TAbstractTest.CheckEquals(expected, actual: Boolean; msg: string);
  1623. begin
  1624.   FCheckCalled := True;
  1625.   if (expected <> actual) then
  1626.     FailNotEquals(BoolToStr(expected), BoolToStr(actual), msg, CallerAddr);
  1627. end;
  1628. procedure TAbstractTest.CheckNotEquals(expected, actual: Boolean; msg: string);
  1629. begin
  1630.   FCheckCalled := True;
  1631.   if (expected = actual) then
  1632.     FailEquals(BoolToStr(expected), BoolToStr(actual), msg, CallerAddr);
  1633. end;
  1634. { [KGS] IntToBin: Elected not to add to TestFrameWork interface,
  1635.         many people already have a self made version: }
  1636. function IntToBin(const value, digits: longword): string;
  1637. const
  1638.   ALL_32_BIT_0 = '00000000000000000000000000000000';
  1639. var
  1640.   counter: integer;
  1641.   pow:     integer;
  1642. begin
  1643.   Result := ALL_32_BIT_0;
  1644.   SetLength(Result, digits);
  1645.   pow := 1 shl (digits - 1);
  1646.   if value <> 0 then
  1647.   for counter := 0 to digits - 1 do
  1648.   begin
  1649.     if (value and (pow shr counter)) <> 0 then
  1650.       Result[counter+1] := '1';
  1651.   end;
  1652. end;
  1653. procedure TAbstractTest.CheckEqualsBin(expected, actual: longword;
  1654.                                        msg: string = ''; digits: integer=32);
  1655. begin
  1656.   FCheckCalled := True;
  1657.   if expected <> actual then
  1658.     FailNotEquals(IntToBin(expected, digits), IntToBin(actual, digits), msg, CallerAddr);
  1659. end;
  1660. procedure TAbstractTest.CheckNotEqualsBin(expected, actual: longword;
  1661.                                        msg: string = ''; digits: integer=32);
  1662. begin
  1663.   FCheckCalled := True;
  1664.   if (expected = actual) then
  1665.     FailEquals(IntToBin(expected, digits), IntToBin(actual, digits), msg, CallerAddr);
  1666. end;
  1667. procedure TAbstractTest.CheckEqualsHex(expected, actual: longword;
  1668.                                        msg: string = ''; digits: integer=8);
  1669. begin
  1670.   FCheckCalled := True;
  1671.   if expected <> actual then
  1672.     FailNotEquals(IntToHex(expected, digits), IntToHex(actual, digits), msg, CallerAddr);
  1673. end;
  1674. procedure TAbstractTest.CheckNotEqualsHex(expected, actual: longword;
  1675.                                        msg: string = ''; digits: integer=8);
  1676. begin
  1677.   FCheckCalled := True;
  1678.   if (expected = actual) then
  1679.     FailEquals(IntToHex(expected, digits), IntToHex(actual, digits), msg, CallerAddr);
  1680. end;
  1681. procedure TAbstractTest.CheckSame(expected, actual: TObject; msg: string);
  1682. begin
  1683.   FCheckCalled := True;
  1684.     if (expected <> actual) then
  1685.       FailNotSame(PtrToStr(Pointer(expected)), PtrToStr(Pointer(actual)), msg, CallerAddr);
  1686. end;
  1687. procedure TAbstractTest.CheckNotNull(obj: TObject; msg: string);
  1688. begin
  1689.   FCheckCalled := True;
  1690.     if obj = nil then
  1691.        FailNotSame('object', PtrToStr(Pointer(obj)), msg, CallerAddr);
  1692. end;
  1693. procedure TAbstractTest.CheckNull(obj: TObject; msg: string);
  1694. begin
  1695.   FCheckCalled := True;
  1696.     if obj <> nil then
  1697.        FailNotSame('nil', PtrToStr(Pointer(obj)), msg, CallerAddr);
  1698. end;
  1699. function TAbstractTest.NotEqualsErrorMessage(expected, actual: WideString; msg: string): WideString;
  1700. begin
  1701.     if (msg <> '') then
  1702.         msg := msg + ', ';
  1703.     Result := Format( sExpButWasFmt , [msg, expected, actual])
  1704. end;
  1705. function TAbstractTest.EqualsErrorMessage(expected, actual: WideString; msg: string): WideString;
  1706. begin
  1707.     if (msg <> '') then
  1708.         msg := msg + ', ';
  1709.     Result := Format( sExpAndActualFmt, [msg, expected])
  1710. end;
  1711. function TAbstractTest.NotSameErrorMessage(expected, actual, msg: string): WideString;
  1712. begin
  1713.     if (msg <> '') then
  1714.         msg := msg + ', ';
  1715.     Result := Format( sExpButWasFmt, [msg, expected, actual])
  1716. end;
  1717. function TAbstractTest.BoolToStr(ABool: Boolean): string;
  1718. begin
  1719.   Result := BooleanIdents[aBool];
  1720. end;
  1721. procedure TAbstractTest.StartExpectingException(e: ExceptionClass);
  1722. begin
  1723.   StopExpectingException;
  1724.   FExpectedException := e;
  1725. end;
  1726. procedure TAbstractTest.StopExpectingException(msg :string);
  1727. begin
  1728.   try
  1729.     if FExpectedException <> nil then
  1730.     begin
  1731.       Fail( Format( 'Expected exception "%s" but there was none. %s',
  1732.                                         [FExpectedException.ClassName,
  1733.                                         Msg]),
  1734.                                         CallerAddr);
  1735.     end;
  1736.   finally
  1737.     FExpectedException := nil;
  1738.   end;
  1739. end;
  1740. {$IFNDEF CLR}
  1741. procedure TAbstractTest.CheckMethodIsNotEmpty(MethodPointer: pointer);
  1742. const
  1743.   AssemblerRet = $C3;
  1744. begin
  1745.   if byte(MethodPointer^) = AssemblerRet then
  1746.     Fail('Empty test', MethodPointer);
  1747. end;
  1748. {$ENDIF}
  1749. procedure TAbstractTest.CheckException(AMethod: TTestMethod; AExceptionClass: TClass; msg :string);
  1750. begin
  1751.   FCheckCalled := True;
  1752.   try
  1753.     Invoke(AMethod);
  1754.   except
  1755.     on e :Exception do
  1756.     begin
  1757.       if  not Assigned(AExceptionClass) then
  1758.         raise
  1759.       else if not e.ClassType.InheritsFrom(AExceptionClass) then
  1760.         FailNotEquals(AExceptionClass.ClassName, e.ClassName, msg, CallerAddr)
  1761.       else
  1762.         AExceptionClass := nil;
  1763.     end;
  1764.   end;
  1765.   if Assigned(AExceptionClass) then
  1766.     FailNotEquals(AExceptionClass.ClassName, 'nothing', msg, CallerAddr)
  1767. end;
  1768. procedure TAbstractTest.CheckEquals(expected, actual: TClass; msg: string);
  1769. begin
  1770.   FCheckCalled := True;
  1771.  if expected <> actual then
  1772.  begin
  1773.    if expected = nil then
  1774.      FailNotEquals('nil', actual.ClassName, msg, CallerAddr)
  1775.    else if actual = nil then
  1776.      FailNotEquals(expected.ClassName, 'nil', msg, CallerAddr)
  1777.    else
  1778.      FailNotEquals(expected.ClassName, actual.ClassName, msg, CallerAddr)
  1779.  end;
  1780. end;
  1781. procedure TAbstractTest.CheckInherits(expected, actual: TClass; msg: string);
  1782. begin
  1783.   FCheckCalled := True;
  1784.   if expected = nil then
  1785.     FailNotEquals('nil', actual.ClassName, msg, CallerAddr)
  1786.   else if actual = nil then
  1787.     FailNotEquals(expected.ClassName, 'nil', msg, CallerAddr)
  1788.   else if not actual.InheritsFrom(expected) then
  1789.     FailNotEquals(expected.ClassName, actual.ClassName, msg, CallerAddr)
  1790. end;
  1791. procedure TAbstractTest.CheckIs(AObject: TObject; AClass: TClass; msg: string);
  1792. begin
  1793.   FCheckCalled := True;
  1794.   Assert(AClass <> nil);
  1795.   if AObject = nil then
  1796.     FailNotEquals(AClass.ClassName, 'nil', msg, CallerAddr)
  1797.   else if not AObject.ClassType.InheritsFrom(AClass) then
  1798.     FailNotEquals(AClass.ClassName, AObject.ClassName, msg, CallerAddr)
  1799. end;
  1800. function TAbstractTest.GetGUIObject: TObject;
  1801. begin
  1802.   Result := FGUIObject;
  1803. end;
  1804. procedure TAbstractTest.SetGUIObject(const guiObject: TObject);
  1805. begin
  1806.   FGUIObject := guiObject;
  1807. end;
  1808. function TAbstractTest.GetFailsOnNoChecksExecuted: Boolean;
  1809. begin
  1810.   Result := FFailsOnNoChecksExecuted;
  1811. end;
  1812. procedure TAbstractTest.SetFailsOnNoChecksExecuted(const Value: Boolean);
  1813. begin
  1814.   FFailsOnNoChecksExecuted := Value;
  1815. end;
  1816. function TAbstractTest.GetFailsOnMemoryLeak: Boolean;
  1817. begin
  1818.   Result := FFailsOnMemoryLeak;
  1819. end;
  1820. procedure TAbstractTest.SetFailsOnMemoryLeak(const Value: Boolean);
  1821. begin
  1822.   FFailsOnMemoryLeak := Value;
  1823. end;
  1824. function TAbstractTest.GetTestMethodInvoked: Boolean;
  1825. begin
  1826.   Result := FTestMethodInvoked;
  1827. end;
  1828. procedure TAbstractTest.SetTestMethodInvoked(const Value: Boolean);
  1829. begin
  1830.   FTestMethodInvoked := True;
  1831. end;
  1832. function TAbstractTest.GetAllowedMemoryLeakSize: Integer;
  1833. // Array[0] reserved for property AllowedLeakSize and remainder for values entered by SetAllowedLeakArray
  1834. var
  1835.   i: Integer;
  1836. begin
  1837.   Result := FAllowedLeakList[0];
  1838.   if (result = 0) then
  1839.   begin   // The user may have set the values using SetAllowedLeakArray
  1840.     for I := 0 to Length(FAllowedLeakList) - 1 do    // Iterate
  1841.     begin
  1842.       if FAllowedLeakList[0] <> 0 then
  1843.       begin
  1844.         result := FAllowedLeakList[i];
  1845.         break;
  1846.       end;
  1847.     end;    // for
  1848.   end;
  1849. end;
  1850. procedure TAbstractTest.SetAllowedMemoryLeakSize(const NewSize: Integer);
  1851. begin
  1852.   FAllowedLeakList[0] := NewSize;
  1853. end;
  1854. function TAbstractTest.GetFailsOnMemoryRecovery: Boolean;
  1855. begin
  1856.   Result := FFailsOnMemoryRecovery;
  1857. end;
  1858. procedure TAbstractTest.SetFailsOnMemoryRecovery(const Value: Boolean);
  1859. begin
  1860.   FFailsOnMemoryRecovery := Value;
  1861. end;
  1862. procedure TAbstractTest.SetAllowedLeakArray(AllowedList: array of Integer);
  1863. var
  1864.   I: Integer;
  1865. begin // Note the 0th element is reserved for old code value.
  1866.   if Length(AllowedList) >= Length(FAllowedLeakList) then
  1867.     fail('Too many values in for AllowedLeakArray. Limit = ' +
  1868.       IntToStr(Length(FAllowedLeakList) - 1));
  1869.   for I := 1 to Length(FAllowedLeakList) - 1 do
  1870.   begin
  1871.     if I <= Length(AllowedList) then
  1872.       FAllowedLeakList[I] := AllowedList[I-1]
  1873.     else
  1874.       FAllowedLeakList[I] := 0;
  1875.   end;
  1876. end;
  1877. function  TAbstractTest.GetAllowedLeaksIterator: TListIterator;
  1878. begin
  1879.   FAllowedLeakListIndex := 0;
  1880.   result := GetAllowedLeak;
  1881. end;
  1882. function TAbstractTest.GetAllowedLeak: Integer;
  1883. begin // Auto Iterator
  1884.   if FAllowedLeakListIndex >= Length(FAllowedLeakList) then
  1885.     Result := 0
  1886.   else
  1887.   begin
  1888.     Result := FAllowedLeakList[FAllowedLeakListIndex];
  1889.     Inc(FAllowedLeakListIndex);
  1890.   end;
  1891. end;
  1892. function TAbstractTest.GetIgnoreSetUpTearDownLeaks: Boolean;
  1893. begin
  1894.   Result := FIgnoreSetUpTearDownLeaks;
  1895. end;
  1896. procedure TAbstractTest.SetIgnoreSetUpTearDownLeaks(const Value: Boolean);
  1897. begin
  1898.   FIgnoreSetUpTearDownLeaks := Value;
  1899. end;
  1900. function TAbstractTest.GetMemoryLeakIgnoredInSetupTearDown: Boolean;
  1901. begin
  1902.   Result := FMemoryLeakIgnoredInSetupTearDown;
  1903. end;
  1904. procedure TAbstractTest.SetMemoryLeakIgnoredInSetupTearDown(
  1905.   const Value: Boolean);
  1906. begin
  1907.   FMemoryLeakIgnoredInSetupTearDown := Value;
  1908. end;
  1909. { TTestCase }
  1910. constructor TTestCase.Create(MethodName: string);
  1911. {$IFNDEF CLR}
  1912. var
  1913.   RunMethod: TMethod;
  1914. {$ENDIF}
  1915. begin
  1916.   assert(length(MethodName) >0);
  1917. {$IFNDEF CLR}
  1918.   assert(assigned(MethodAddress(MethodName)));
  1919. {$ELSE}
  1920.   assert(MethodName <> '');
  1921. {$ENDIF}
  1922.   inherited Create(MethodName);
  1923. {$IFDEF CLR}
  1924.   FMethod := MethodName;
  1925. {$ELSE}
  1926.   RunMethod.code := MethodAddress(MethodName);
  1927.   RunMethod.Data := self;
  1928.   FMethod := TTestMethod(RunMethod);
  1929.   assert(assigned(FMethod));
  1930. {$ENDIF}
  1931. end;
  1932. procedure TTestCase.Invoke(AMethod: TTestMethod);
  1933. {$IFDEF CLR}
  1934. var
  1935.   Args: array of System.Object;
  1936. {$ENDIF}
  1937. begin
  1938.   FTestMethodInvoked := True;
  1939. {$IFDEF CLR}
  1940.   Args := nil;
  1941.   try
  1942.     GetType.InvokeMember(AMethod, BindingFlags.Public or BindingFlags.Instance or BindingFlags.InvokeMethod, nil, Self, Args);
  1943.   except
  1944.     on E:TargetInvocationException do
  1945.       raise E.InnerException;
  1946.   end;
  1947. {$ELSE}
  1948.   AMethod;
  1949. {$ENDIF}
  1950. end;
  1951. procedure TTestCase.RunWithFixture(testResult: TTestResult);
  1952. begin
  1953.   assert(assigned(testResult));
  1954.   FFailsOnNoChecksExecuted := testResult.FailsIfNoChecksExecuted;
  1955.   FFailsOnMemoryLeak := testResult.FailsIfMemoryLeaked;
  1956.   FIgnoreSetUpTearDownLeaks := testResult.IgnoresMemoryLeakInSetUpTearDown;
  1957.   if testResult.ShouldRunTest(self) then
  1958.   begin
  1959.     inc(testResult.FRunTests);
  1960.     inherited;
  1961.   end;
  1962. end;
  1963. procedure TTestCase.RunTest(testResult: TTestResult);
  1964. begin
  1965.   assert(assigned(FMethod), 'Method "' + FTestName + '" not found');
  1966.   FExpectedException := nil;
  1967.   try
  1968.     try
  1969. {$IFDEF CLR}
  1970.       testResult.FMethodPtr := nil;
  1971. {$ELSE}
  1972.       CheckMethodIsNotEmpty(tMethod(FMethod).Code);
  1973.       testResult.FMethodPtr := tMethod(FMethod).Code;
  1974. {$ENDIF}
  1975.       FCheckCalled := False;
  1976.       Invoke(FMethod);
  1977.       if FFailsOnNoChecksExecuted and (not FCheckCalled) then
  1978.         Fail('No checks executed in TestCase', testResult.FMethodPtr);
  1979.       StopExpectingException;
  1980.     except
  1981.       on E: ETestFailure  do
  1982.       begin
  1983.         raise;
  1984.       end;
  1985.       on E: Exception  do
  1986.       begin
  1987.         if  not Assigned(FExpectedException) then
  1988.           raise
  1989.         else if not E.ClassType.InheritsFrom(fExpectedException) then
  1990.           FailNotEquals(fExpectedException.ClassName, E.ClassName, 'unexpected exception', ExceptAddr);
  1991.       end
  1992.     end;
  1993.   finally
  1994.     FExpectedException := nil;
  1995.   end;
  1996. end;
  1997. procedure TTestCase.Run(testResult: TTestResult);
  1998. begin
  1999.   testResult.RunSuite(self);
  2000. end;
  2001. class function TTestCase.Suite: ITestSuite;
  2002. begin
  2003.   Result := TTestSuite.Create(self);
  2004. end;
  2005. { TTestFailure }
  2006. constructor TTestFailure.Create(FailedTest: ITest; thrownException: Exception; Addrs: Pointer; msg: string);
  2007. begin
  2008.   assert(assigned(thrownException));
  2009.   inherited Create;
  2010.   FFailedTest := FailedTest;
  2011.   FThrownExceptionClass := thrownException.ClassType;
  2012.   FThrownExceptionMessage := msg + thrownException.message;
  2013.   FThrownExceptionAddress := Addrs;
  2014.   CaptureStackTrace;
  2015. end;
  2016. constructor TTestFailure.Create(FailedTest: ITest; Addrs: Pointer; msg: string);
  2017. begin
  2018.   inherited Create;
  2019.   FFailedTest := FailedTest;
  2020.   FThrownExceptionClass := EPostTestFailure;
  2021.   FThrownExceptionMessage := msg;
  2022.   FThrownExceptionAddress := Addrs;
  2023.   FStackTrace := '';
  2024. end;
  2025. function TTestFailure.FailedTest: ITest;
  2026. begin
  2027.   Result := FFailedTest;
  2028. end;
  2029. function TTestFailure.ThrownExceptionName: string;
  2030. begin
  2031.   Result := FThrownExceptionClass.ClassName;
  2032. end;
  2033. function TTestFailure.ThrownExceptionMessage: string;
  2034. begin
  2035.   Result := FThrownExceptionMessage;
  2036. end;
  2037. function TTestFailure.ThrownExceptionAddress: pointer;
  2038. begin
  2039.   Result := FThrownExceptionAddress;
  2040. end;
  2041. function TTestFailure.ThrownExceptionClass: TClass;
  2042. begin
  2043.   Result := FThrownExceptionClass;
  2044. end;
  2045. function TTestFailure.LocationInfo: string;
  2046. begin
  2047.   Result := PointerToLocationInfo(ThrownExceptionAddress);
  2048. end;
  2049. function TTestFailure.AddressInfo: string;
  2050. begin
  2051.   Result := PointerToAddressInfo(ThrownExceptionAddress);
  2052. end;
  2053. function TTestFailure.StackTrace: string;
  2054. begin
  2055.   Result := FStackTrace;
  2056. end;
  2057. procedure TTestFailure.CaptureStackTrace;
  2058. {$IFDEF USE_JEDI_JCL}
  2059. var
  2060.   Trace :TStrings;
  2061. {$ENDIF}
  2062. begin
  2063. {$IFDEF USE_JEDI_JCL}
  2064.   Trace := TStringList.Create;
  2065.   try
  2066.     JclDebug.JclLastExceptStackListToStrings(Trace, true);
  2067.     FStackTrace := Trace.Text;
  2068.   finally
  2069.     Trace.Free;
  2070.   end;
  2071. {$ELSE}
  2072. {$IFDEF madExcept}
  2073.   FStackTrace := madStackTrace.StackTrace( false, false, false, nil,
  2074.                                            FThrownExceptionAddress, false,
  2075.                                            false, 0, 0, nil,
  2076.                                            @FThrownExceptionAddress );
  2077. {$ELSE}
  2078.   FStackTrace := '';
  2079. {$ENDIF}
  2080. {$ENDIF}
  2081. end;
  2082. { TTestSuite }
  2083. constructor TTestSuite.Create;
  2084. begin
  2085.   Create(TObject.ClassName);
  2086. end;
  2087. constructor TTestSuite.Create(AName: string);
  2088. begin
  2089.   assert(length(AName) > 0);
  2090.   inherited Create(AName);
  2091.   FTests := TInterfaceList.Create;
  2092. end;
  2093. constructor TTestSuite.Create( testClass: TTestCaseClass);
  2094. begin
  2095.   self.Create(testClass.ClassName);
  2096.   AddTests(testClass);
  2097. end;
  2098. constructor TTestSuite.Create(AName: string; const Tests: array of ITest);
  2099. var
  2100.   i: Integer;
  2101. begin
  2102.   self.Create(AName);
  2103.   for i := Low(Tests) to High(Tests) do begin
  2104.     Self.addTest(Tests[i])
  2105.   end;
  2106. end;
  2107. procedure TTestSuite.AddTest(ATest: ITest);
  2108. begin
  2109.   Assert(Assigned(ATest));
  2110.   FTests.Add(ATest);
  2111. end;
  2112. procedure TTestSuite.AddSuite(suite: ITestSuite);
  2113. begin
  2114.   AddTest(suite);
  2115. end;
  2116. procedure TTestSuite.AddTests(testClass: TTestCaseClass);
  2117. var
  2118.   MethodIter     :  Integer;
  2119.   NameOfMethod   :  string;
  2120.   MethodEnumerator:  TMethodEnumerator;
  2121. begin
  2122.   { call on the method enumerator to get the names of the test
  2123.     cases in the testClass }
  2124.   MethodEnumerator := nil;
  2125.   try
  2126.     MethodEnumerator := TMethodEnumerator.Create(testClass);
  2127.     { make sure we add each test case  to the list of tests }
  2128.     for MethodIter := 0 to MethodEnumerator.Methodcount-1 do
  2129.       begin
  2130.         NameOfMethod := MethodEnumerator.nameOfMethod[MethodIter];
  2131.         self.addTest(testClass.Create(NameOfMethod) as ITest);
  2132.       end;
  2133.   finally
  2134.     MethodEnumerator.free;
  2135.   end;
  2136. end;
  2137. function TTestSuite.CountTestCases: integer;
  2138. var
  2139.   test: ITest;
  2140.   i: Integer;
  2141.   Total:  integer;
  2142. begin
  2143.   assert(assigned(FTests));
  2144.   Total := 0;
  2145.   for i := 0 to FTests.Count - 1 do
  2146.   begin
  2147.     test := FTests[i] as ITest;
  2148.     Total := Total + test.CountTestCases;
  2149.   end;
  2150.   Result := Total;
  2151. end;
  2152. function TTestSuite.CountEnabledTestCases: integer;
  2153. var
  2154.   i: Integer;
  2155.   test: ITest;
  2156.   Total:  Integer;
  2157. begin
  2158.   assert(assigned(FTests));
  2159.   Total := 0;
  2160.   if getEnabled then
  2161.   begin
  2162.     for i := 0 to FTests.Count - 1 do
  2163.     begin
  2164.       test := FTests[i] as ITest;
  2165.       Total := Total + test.CountEnabledTestCases;
  2166.     end;
  2167.   end;
  2168.   Result := Total;
  2169. end;
  2170. procedure TTestSuite.RunTest(testResult: TTestResult);
  2171. var
  2172.   i: Integer;
  2173.   test: ITest;
  2174. begin
  2175.   assert(assigned(testResult));
  2176.   assert(assigned(FTests));
  2177.   testResult.StartSuite(self);
  2178.   for i := 0 to FTests.Count - 1 do
  2179.   begin
  2180.     if testResult.ShouldStop then
  2181.       BREAK;
  2182.     test := FTests[i] as ITest;
  2183.     test.RunWithFixture(testResult);
  2184.   end;
  2185.   testResult.EndSuite(self);
  2186. end;
  2187. function TTestSuite.Tests: IInterfaceList;
  2188. begin
  2189.   Result := FTests;
  2190. end;
  2191. procedure TTestSuite.LoadConfiguration(const iniFile: TCustomIniFile; const section: string);
  2192. var
  2193.   i    : integer;
  2194.   LTests: IInterfaceList;
  2195.   TestSection: string;
  2196. begin
  2197.   inherited LoadConfiguration(iniFile, section);
  2198.   LTests := self.Tests;
  2199.   TestSection := section + '.' + self.GetName;
  2200.   for i := 0 to LTests.count-1 do
  2201.     (LTests[i] as ITest).LoadConfiguration(iniFile, TestSection);
  2202. end;
  2203. procedure TTestSuite.SaveConfiguration(const iniFile: TCustomIniFile; const section: string);
  2204. var
  2205.   i    : integer;
  2206.   LTests: IInterfaceList;
  2207.   TestSection: string;
  2208. begin
  2209.   inherited SaveConfiguration(iniFile, section);
  2210.   LTests := self.Tests;
  2211.   TestSection := section + '.' + self.GetName;
  2212.   for i := 0 to LTests.count-1 do
  2213.     (LTests[i] as ITest).SaveConfiguration(iniFile, TestSection);
  2214. end;
  2215. { ETestFailure }
  2216. constructor ETestFailure.Create;
  2217. begin
  2218.    inherited Create('')
  2219. end;
  2220. constructor ETestFailure.Create(msg: string);
  2221. begin
  2222.    inherited Create(msg)
  2223. end;
  2224. { EBreakingTestFailure }
  2225. constructor EBreakingTestFailure.Create;
  2226. begin
  2227.    inherited Create('')
  2228. end;
  2229. constructor EBreakingTestFailure.Create(msg: string);
  2230. begin
  2231.    inherited Create(msg)
  2232. end;
  2233. { TMemIniFileTrimmed }
  2234. function TMemIniFileTrimmed.ReadString(const Section, Ident,
  2235.   DefaultStr: string): string;
  2236. begin
  2237.   // Trim the result for compatibility with TIniFile
  2238.   Result := Trim(inherited ReadString(Section, Ident, DefaultStr));
  2239. end;
  2240. { TMethodEnumerator }
  2241. constructor TMethodEnumerator.Create(AClass: TClass);
  2242. {$IFDEF CLR}
  2243. var
  2244.   I, L: integer;
  2245.   T: System.Type;
  2246.   Methods: array of MethodInfo;
  2247.   function IsTest(AMethod: MethodInfo): Boolean;
  2248.   var
  2249.     CustomAttr: array of System.Object;
  2250.     I: integer;
  2251.   begin
  2252.     Result := false;
  2253.     if AMethod.IsPublic then
  2254.     begin
  2255.       CustomAttr := AMethod.GetCustomAttributes(false);
  2256.       for I := 0 to System.Array(CustomAttr).Length - 1 do
  2257.       begin
  2258.         if CustomAttr[I].ClassNameIs('TestAttribute') then
  2259.         begin
  2260.           Result := true;
  2261.           Break;
  2262.         end;;
  2263.       end;
  2264.     end;
  2265.   end;
  2266. {$ELSE}
  2267. type
  2268.   TMethodTable = packed record
  2269.     count: SmallInt;
  2270.   //[...methods...]
  2271.   end;
  2272. var
  2273.   table: ^TMethodTable;
  2274.   AName:  ^ShortString;
  2275.   i, j:  Integer;
  2276. {$ENDIF}
  2277. begin
  2278.   inherited Create;
  2279. {$IFDEF CLR}
  2280.   T := AClass.ClassInfo;
  2281.   Methods := T.GetMethods();
  2282.   L := 0;
  2283.   SetLength(FMethodNameList, L);
  2284.   for I := 0 to System.Array(Methods).Length - 1 do
  2285.     if IsTest(Methods[I]) then
  2286.     begin
  2287.       L := L + 1;
  2288.       SetLength(FMethodNameList, L);
  2289.       FMethodNameList[L-1] := Methods[I].Name;
  2290.     end;
  2291. {$ELSE}
  2292.   while aclass <> nil do
  2293.   begin
  2294.     // *** HACK ALERT *** !!!
  2295.     // Review System.MethodName to grok how this method works
  2296.     asm
  2297.       mov  EAX, [aclass]
  2298.       mov  EAX,[EAX].vmtMethodTable { fetch pointer to method table }
  2299.       mov  [table], EAX
  2300.     end;
  2301.     if table <> nil then
  2302.     begin
  2303.       AName  := Pointer(PChar(table) + 8);
  2304.       for i := 1 to table.count do
  2305.       begin
  2306.         // check if we've seen the method name
  2307.         j := Low(FMethodNameList);
  2308.         while (j <= High(FMethodNameList))
  2309.         and (AName^ <> FMethodNameList[j]) do
  2310.           inc(j);
  2311.         // if we've seen the name, then the method has probably been overridden
  2312.         if j > High(FMethodNameList) then
  2313.         begin
  2314.           SetLength(FMethodNameList,length(FMethodNameList)+1);
  2315.           FMethodNameList[j] := AName^;
  2316.         end;
  2317.         AName := Pointer(PChar(AName) + length(AName^) + 7)
  2318.       end;
  2319.     end;
  2320.     aclass := aclass.ClassParent;
  2321.   end;
  2322. {$ENDIF}
  2323. end;
  2324. function TMethodEnumerator.GetMethodCount: Integer;
  2325. begin
  2326.   Result := Length(FMethodNameList);
  2327. end;
  2328. function TMethodEnumerator.GetNameOfMethod(idx: integer): string;
  2329. begin
  2330.   Result := FMethodNameList[idx];
  2331. end;
  2332. { Convenience routines }
  2333. function  TestSuite(AName: string; const Tests: array of ITest): ITestSuite;
  2334. begin
  2335.    Result := TTestSuite.Create(AName, Tests);
  2336. end;
  2337. { test registry }
  2338. var
  2339.   __TestRegistry: ITestSuite = nil;
  2340. procedure RegisterTestInSuite(rootSuite: ITestSuite; path: string; test: ITest);
  2341. var
  2342.   pathRemainder:  string;
  2343.   suiteName:  string;
  2344.   targetSuite:  ITestSuite;
  2345.   suite:  ITestSuite;
  2346.   currentTest:  ITest;
  2347.   Tests:  IInterfaceList;
  2348.   dotPos:  Integer;
  2349.   i: Integer;
  2350. begin
  2351.   if (path = '') then
  2352.   begin
  2353.     // End any recursion
  2354.     rootSuite.addTest(test);
  2355.   end
  2356.   else
  2357.   begin
  2358.     // Split the path on the dot (.)
  2359.     dotPos := Pos('.', Path);
  2360.     if (dotPos <= 0) then dotPos := Pos('', Path);
  2361.     if (dotPos <= 0) then dotPos := Pos('/', Path);
  2362.     if (dotPos > 0) then
  2363.     begin
  2364.       suiteName := Copy(path, 1, dotPos - 1);
  2365.       pathRemainder := Copy(path, dotPos + 1, length(path) - dotPos);
  2366.     end
  2367.     else
  2368.     begin
  2369.       suiteName := path;
  2370.       pathRemainder := '';
  2371.     end;
  2372.     Tests := rootSuite.Tests;
  2373.     // Check to see if the path already exists
  2374.     targetSuite := nil;
  2375.     Tests := rootSuite.Tests;
  2376.     for i := 0 to Tests.count -1 do
  2377.     begin
  2378.       currentTest := Tests[i] as ITest;
  2379. {$IFDEF CLR}
  2380.       if Supports(currentTest, ITestSuite, suite) then
  2381. {$ELSE}
  2382.       currentTest.queryInterface(ITestSuite, suite);
  2383.       if Assigned(suite) then
  2384. {$ENDIF}
  2385.       begin
  2386.         if (currentTest.GetName = suiteName) then
  2387.         begin
  2388.           targetSuite := suite;
  2389.           break;
  2390.         end;
  2391.       end;
  2392.     end;
  2393.     if not assigned(targetSuite) then
  2394.     begin
  2395.       targetSuite := TTestSuite.Create(suiteName);
  2396.       rootSuite.addTest(targetSuite);
  2397.     end;
  2398.     RegisterTestInSuite(targetSuite, pathRemainder, test);
  2399.   end;
  2400. end;
  2401. procedure CreateRegistry;
  2402. var
  2403.   MyName :AnsiString;
  2404. begin
  2405. {$IFDEF CLR}
  2406.   MyName := ExtractFileName(ParamStr(0));
  2407. {$ELSE}
  2408.   SetLength(MyName, 1024);
  2409.   GetModuleFileName(hInstance, PChar(MyName), Length(MyName));
  2410.   MyName := Trim(PChar(MyName));
  2411.   MyName := ExtractFileName(MyName);
  2412. {$ENDIF}
  2413.   __TestRegistry := TTestSuite.Create(MyName);
  2414. end;
  2415. procedure RegisterTest(SuitePath: string; test: ITest);
  2416. begin
  2417.   assert(assigned(test));
  2418.   if __TestRegistry = nil then CreateRegistry;
  2419.   RegisterTestInSuite(__TestRegistry, SuitePath, test);
  2420. end;
  2421. procedure RegisterTest(test: ITest);
  2422. begin
  2423.   RegisterTest('', test);
  2424. end;
  2425. procedure RegisterTests(SuitePath: string; const Tests: array of ITest);
  2426. var
  2427.   i: Integer;
  2428. begin
  2429.   for i := Low(Tests) to High(Tests) do begin
  2430.     TestFramework.RegisterTest(SuitePath, Tests[i])
  2431.   end
  2432. end;
  2433. procedure RegisterTests(const Tests: array of ITest);
  2434. begin
  2435.   RegisterTests('', Tests);
  2436. end;
  2437. function RegisteredTests: ITestSuite;
  2438. begin
  2439.   Result := __TestRegistry;
  2440. end;
  2441. function RunTest(suite: ITest; listeners: array of ITestListener): TTestResult; overload;
  2442. var
  2443.   i        : Integer;
  2444. begin
  2445.   Result := TTestResult.Create;
  2446.   for i := low(listeners) to high(listeners) do
  2447.       result.addListener(listeners[i]);
  2448.   if suite <> nil then
  2449.     suite.Run(result);
  2450. end;
  2451. function RunRegisteredTests(listeners: array of ITestListener): TTestResult;
  2452. begin
  2453.   Result := RunTest(RegisteredTests, listeners);
  2454. end;
  2455. procedure ClearRegistry;
  2456. begin
  2457.   __TestRegistry := nil;
  2458. end;
  2459. initialization
  2460. {$IFDEF LINUX}
  2461.   InitPerformanceCounter;
  2462. {$ENDIF}
  2463. finalization
  2464.   ClearRegistry;
  2465. end.