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

Email服务器

开发平台:

Delphi

  1. { $Id: GUITestRunner.pas,v 1.129 2007/01/06 02:17:23 judc Exp $ }
  2. {: DUnit: An XTreme testing framework for Delphi programs.
  3.    @author  The DUnit Group.
  4.    @version $Revision: 1.129 $ 2001/03/08 uberto
  5. }
  6. (*
  7.  * The contents of this file are subject to the Mozilla Public
  8.  * License Version 1.1 (the "License"); you may not use this file
  9.  * except in compliance with the License. You may obtain a copy of
  10.  * the License at http://www.mozilla.org/MPL/
  11.  *
  12.  * Software distributed under the License is distributed on an "AS
  13.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  14.  * implied. See the License for the specific language governing
  15.  * rights and limitations under the License.
  16.  *
  17.  * The Original Code is DUnit.
  18.  *
  19.  * The Initial Developers of the Original Code are Kent Beck, Erich Gamma,
  20.  * and Juancarlo A眅z.
  21.  * Portions created The Initial Developers are Copyright (C) 1999-2000.
  22.  * Portions created by The DUnit Group are Copyright (C) 2000-2004.
  23.  * All rights reserved.
  24.  *
  25.  * Contributor(s):
  26.  * Kent Beck <kentbeck@csi.com>
  27.  * Erich Gamma <Erich_Gamma@oti.com>
  28.  * Juanco A馿z <juanco@users.sourceforge.net>
  29.  * Chris Morris <chrismo@users.sourceforge.net>
  30.  * Jeff Moore <JeffMoore@users.sourceforge.net>
  31.  * Kenneth Semeijn <dunit@designtime.demon.nl>
  32.  * Uberto Barbini <uberto@usa.net>
  33.  * Brett Shearer <BrettShearer@users.sourceforge.net>
  34.  * Kris Golko <neuromancer@users.sourceforge.net>
  35.  * The DUnit group at SourceForge <http://dunit.sourceforge.net>
  36.  *
  37.  *)
  38. unit GUITestRunner;
  39. interface
  40. uses
  41.   TestFramework,
  42.   Windows,
  43.   Math,
  44.   Graphics, Controls, Forms, 
  45.   ComCtrls, ExtCtrls, StdCtrls, ImgList, Buttons, Menus, ActnList,
  46.   Classes, IniFiles, ToolWin;
  47. const
  48.   {: Section of the dunit.ini file where GUI information will be stored }
  49.   cnConfigIniSection = 'GUITestRunner Config';
  50.   {: Color constants for the progress bar and failure details panel }
  51.   clOK      = clGreen;
  52.   clFAILURE = clFuchsia;
  53.   clERROR   = clRed;
  54.   {: Indexes of the color images used in the test tree and failure list }
  55.   imgNONE     = 0;
  56.   imgRUNNING  = 1;
  57.   imgRUN      = 2;
  58.   imgHASPROPS = 3;
  59.   imgFAILED   = 4;
  60.   imgERROR    = 5;
  61.   {: Indexes of the images used for test tree checkboxes }
  62.   imgDISABLED        = 1;
  63.   imgPARENT_DISABLED = 2;
  64.   imgENABLED         = 3;
  65. type
  66.   {: Function type used by the TDUnitDialog.ApplyToTests method
  67.      @param item  The ITest instance on which to act
  68.      @return true if processing should continue, false otherwise
  69.   }
  70.   TTestFunc = function (item :ITest):Boolean of object;
  71.   TGUITestRunner = class(TForm, ITestListener, ITestListenerX)
  72.     StateImages: TImageList;
  73.     RunImages: TImageList;
  74.     DialogActions: TActionList;
  75.     SelectAllAction: TAction;
  76.     DeselectAllAction: TAction;
  77.     SelectFailedAction: TAction;
  78.     MainMenu: TMainMenu;
  79.     TestTreeMenu: TMenuItem;
  80.     SelectAllItem: TMenuItem;
  81.     DeselectAllItem: TMenuItem;
  82.     SelectFailedItem: TMenuItem;
  83.     FileMenu: TMenuItem;
  84.     SaveConfigurationAction: TAction;
  85.     AutoSaveAction: TAction;
  86.     SaveConfigurationItem: TMenuItem;
  87.     AutoSaveItem: TMenuItem;
  88.     RestoreSavedAction: TAction;
  89.     RestoreSavedConfigurationItem: TMenuItem;
  90.     ViewMenu: TMenuItem;
  91.     HideErrorBoxItem: TMenuItem;
  92.     BodyPanel: TPanel;
  93.     ErrorBoxVisibleAction: TAction;
  94.     TopPanel: TPanel;
  95.     TreePanel: TPanel;
  96.     TestTree: TTreeView;
  97.     ResultsPanel: TPanel;
  98.     ProgressPanel: TPanel;
  99.     ResultsView: TListView;
  100.     FailureListView: TListView;
  101.     ErrorBoxPanel: TPanel;
  102.     ErrorBoxSplitter: TSplitter;
  103.     ResultsSplitter: TSplitter;
  104.     AutoChangeFocusItem: TMenuItem;
  105.     TopProgressPanel: TPanel;
  106.     ProgressBar: TProgressBar;
  107.     pnlProgresslabel: TPanel;
  108.     ScorePanel: TPanel;
  109.     ScoreLabel: TPanel;
  110.     ScoreBar: TProgressBar;
  111.     pmTestTree: TPopupMenu;
  112.     pmiSelectAll: TMenuItem;
  113.     pmiDeselectAll: TMenuItem;
  114.     pmiSelectFailed: TMenuItem;
  115.     HideTestNodesAction: TAction;
  116.     CollapseLowestSuiteNodesItem: TMenuItem;
  117.     CollapseLowestSuiteNodes1: TMenuItem;
  118.     HideTestNodesOnOpenAction: TAction;
  119.     HideTestNodesItem: TMenuItem;
  120.     ExpandAllNodesAction: TAction;
  121.     TestTreeMenuSeparator: TMenuItem;
  122.     ExpandAllItem: TMenuItem;
  123.     TestTreeLocalMenuSeparator: TMenuItem;
  124.     ExpandAll2: TMenuItem;
  125.     lblTestTree: TLabel;
  126.     RunAction: TAction;
  127.     ExitAction: TAction;
  128.     BreakOnFailuresAction: TAction;
  129.     BreakonFailuresItem: TMenuItem;
  130.     ShowTestedNodeAction: TAction;
  131.     SelectTestedNodeItem: TMenuItem;
  132.     ErrorMessagePopup: TPopupMenu;
  133.     CopyFailureMessage: TMenuItem;
  134.     CopyMessageToClipboardAction: TAction;
  135.     ActionsMenu: TMenuItem;
  136.     CopyMessagetoCllipboardItem: TMenuItem;
  137.     LbProgress: TLabel;
  138.     UseRegistryAction: TAction;
  139.     UseRegistryItem: TMenuItem;
  140.     ErrorMessageRTF: TRichEdit;
  141.     SelectCurrentAction: TAction;
  142.     DeselectCurrentAction: TAction;
  143.     SelectCurrent1: TMenuItem;
  144.     DeselectCurrent1: TMenuItem;
  145.     ActionsImages: TImageList;
  146.     CloseItem: TMenuItem;
  147.     RunItem: TMenuItem;
  148.     StopAction: TAction;
  149.     StopActionItem: TMenuItem;
  150.     ToolBar1: TToolBar;
  151.     SelectAllButton: TToolButton;
  152.     DeselectAllButton: TToolButton;
  153.     ToolButton1: TToolButton;
  154.     SelectFailedButton: TToolButton;
  155.     ToolButton2: TToolButton;
  156.     SelectCurrentButton: TToolButton;
  157.     DeselectCurrentButton: TToolButton;
  158.     ToolButton3: TToolButton;
  159.     ToolButton4: TToolButton;
  160.     ToolButton5: TToolButton;
  161.     Alt_R_RunAction: TAction;
  162.     Alt_S_StopAction: TAction;
  163.     N1: TMenuItem;
  164.     DeselectCurrent2: TMenuItem;
  165.     SelectCurrent2: TMenuItem;
  166.     N2: TMenuItem;
  167.     CopyProcnameToClipboardAction: TAction;
  168.     N3: TMenuItem;
  169.     Copytestnametoclipboard1: TMenuItem;
  170.     N4: TMenuItem;
  171.     Copytestnametoclipboard2: TMenuItem;
  172.     RunSelectedTestAction: TAction;
  173.     N5: TMenuItem;
  174.     Runcurrenttest1: TMenuItem;
  175.     N6: TMenuItem;
  176.     Runcurrenttest2: TMenuItem;
  177.     RunSelectedTestItem: TMenuItem;
  178.     RunSelectedTestButton: TToolButton;
  179.     GoToNextSelectedTestAction: TAction;
  180.     GoToPrevSelectedTestAction: TAction;
  181.     N7: TMenuItem;
  182.     GoToNextSelectedNode1: TMenuItem;
  183.     GoToPreviousSelectedNode1: TMenuItem;
  184.     N8: TMenuItem;
  185.     GoToNextSelectedNode2: TMenuItem;
  186.     GoToPreviousSelectedNode2: TMenuItem;
  187.     FailIfNoChecksExecuted: TMenuItem;
  188.     FailIfNoChecksExecutedAction: TAction;
  189.     FailTestCaseIfMemoryLeaked: TMenuItem;
  190.     FailTestCaseIfMemoryLeakedAction: TAction;
  191.     TestCaseProperty: TPopupMenu;
  192.     TestCaseProperties: TMenuItem;
  193.     N10: TMenuItem;
  194.     FailNoCheckExecutedMenuItem: TMenuItem;
  195.     FailsOnMemoryLeakMenuItem: TMenuItem;
  196.     N11: TMenuItem;
  197.     TestCasePopup: TMenuItem;
  198.     FailsOnMemoryRecoveryMenuItem: TMenuItem;
  199.     AllowedLeakSizeMemuItem: TMenuItem;
  200.     ShowTestCaseswithRunTimeProperties: TMenuItem;
  201.     ShowTestCasesWithRunTimePropertiesAction: TAction;
  202.     N9: TMenuItem;
  203.     WarnOnFailTestOverride: TMenuItem;
  204.     WarnOnFailTestOverrideAction: TAction;
  205.     N12: TMenuItem;
  206.     TestCasePropertiesAction: TAction;
  207.     PropertyPopUpAction: TAction;
  208.     N13: TMenuItem;
  209.     Previous1: TMenuItem;
  210.     Next1: TMenuItem;
  211.     RunSelectedTest1: TMenuItem;
  212.     RunSelectedTestAltAction: TAction;
  213.     N14: TMenuItem;
  214.     ReportMemoryLeakTypeOnShutdown: TMenuItem;
  215.     IgnoreMemoryLeakInSetUpTearDown: TMenuItem;
  216.     IgnoreMemoryLeakInSetUpTearDownAction: TAction;
  217.     ReportMemoryLeakTypeOnShutdownAction: TAction;
  218.     TestCaseIgnoreSetUpTearDownLeaksMenuItem: TMenuItem;
  219.     procedure FormCreate(Sender: TObject);
  220.     procedure TestTreeClick(Sender: TObject);
  221.     procedure FailureListViewSelectItem(Sender: TObject; Item: TListItem;
  222.       Selected: Boolean);
  223.     procedure FailureListViewClick(Sender: TObject);
  224.     procedure TestTreeKeyPress(Sender: TObject; var Key: Char);
  225.     procedure SelectAllActionExecute(Sender: TObject);
  226.     procedure DeselectAllActionExecute(Sender: TObject);
  227.     procedure SelectFailedActionExecute(Sender: TObject);
  228.     procedure SaveConfigurationActionExecute(Sender: TObject);
  229.     procedure RestoreSavedActionExecute(Sender: TObject);
  230.     procedure AutoSaveActionExecute(Sender: TObject);
  231.     procedure ErrorBoxVisibleActionExecute(Sender: TObject);
  232.     procedure ErrorBoxSplitterMoved(Sender: TObject);
  233.     procedure ErrorBoxPanelResize(Sender: TObject);
  234.     procedure HideTestNodesActionExecute(Sender: TObject);
  235.     procedure HideTestNodesOnOpenActionExecute(Sender: TObject);
  236.     procedure ExpandAllNodesActionExecute(Sender: TObject);
  237.     procedure RunActionExecute(Sender: TObject);
  238.     procedure ExitActionExecute(Sender: TObject);
  239.     procedure BreakOnFailuresActionExecute(Sender: TObject);
  240.     procedure FormDestroy(Sender: TObject);
  241.     procedure ShowTestedNodeActionExecute(Sender: TObject);
  242.     procedure CopyMessageToClipboardActionExecute(Sender: TObject);
  243.     procedure UseRegistryActionExecute(Sender: TObject);
  244.     procedure RunActionUpdate(Sender: TObject);
  245.     procedure CopyMessageToClipboardActionUpdate(Sender: TObject);
  246.     procedure SelectCurrentActionExecute(Sender: TObject);
  247.     procedure DeselectCurrentActionExecute(Sender: TObject);
  248.     procedure StopActionExecute(Sender: TObject);
  249.     procedure StopActionUpdate(Sender: TObject);
  250.     procedure TestTreeChange(Sender: TObject; Node: TTreeNode);
  251.     procedure CopyProcnameToClipboardActionExecute(Sender: TObject);
  252.     procedure CopyProcnameToClipboardActionUpdate(Sender: TObject);
  253.     procedure RunSelectedTestActionExecute(Sender: TObject);
  254.     procedure RunSelectedTestActionUpdate(Sender: TObject);
  255.     procedure TestTreeMouseDown(Sender: TObject; Button: TMouseButton;
  256.       Shift: TShiftState; X, Y: Integer);
  257.     procedure GoToNextSelectedTestActionExecute(Sender: TObject);
  258.     procedure GoToPrevSelectedTestActionExecute(Sender: TObject);
  259.     procedure FormShow(Sender: TObject);
  260.     procedure FailIfNoChecksExecutedActionExecute(Sender: TObject);
  261.     procedure FailTestCaseIfMemoryLeakedActionExecute(Sender: TObject);
  262.     procedure ShowTestCasesWithRunTimePropertiesActionExecute(
  263.       Sender: TObject);
  264.     procedure WarnOnFailTestOverrideActionExecute(Sender: TObject);
  265.     procedure TestCasePropertiesActionExecute(Sender: TObject);
  266.     procedure Previous1Click(Sender: TObject);
  267.     procedure Next1Click(Sender: TObject);
  268.     procedure TestCasePropertiesMeasureItem(Sender: TObject;
  269.       ACanvas: TCanvas; var Width, Height: Integer);
  270.     procedure TestCasePropertiesDrawItem(Sender: TObject; ACanvas: TCanvas;
  271.       ARect: TRect; Selected: Boolean);
  272.     procedure FailNoCheckExecutedMenuItemDrawItem(Sender: TObject;
  273.       ACanvas: TCanvas; ARect: TRect; Selected: Boolean);
  274.     procedure AllowedLeakSizeMemuItemDrawItem(Sender: TObject;
  275.       ACanvas: TCanvas; ARect: TRect; Selected: Boolean);
  276.     procedure FailsOnMemoryRecoveryMenuItemDrawItem(Sender: TObject;
  277.       ACanvas: TCanvas; ARect: TRect; Selected: Boolean);
  278.     procedure FailsOnMemoryLeakMenuItemDrawItem(Sender: TObject;
  279.       ACanvas: TCanvas; ARect: TRect; Selected: Boolean);
  280.     procedure pmTestTreePopup(Sender: TObject);
  281.     procedure FailNoCheckExecutedMenuItemClick(Sender: TObject);
  282.     procedure AllowedLeakSizeMemuItemClick(Sender: TObject);
  283.     procedure FailsOnMemoryLeakMenuItemClick(Sender: TObject);
  284.     procedure FailsOnMemoryRecoveryMenuItemClick(Sender: TObject);
  285.     procedure RunSelectedTestAltActionExecute(Sender: TObject);
  286.     procedure Previous1DrawItem(Sender: TObject; ACanvas: TCanvas;
  287.       ARect: TRect; Selected: Boolean);
  288.     procedure RunSelectedTest1DrawItem(Sender: TObject; ACanvas: TCanvas;
  289.       ARect: TRect; Selected: Boolean);
  290.     procedure Next1DrawItem(Sender: TObject; ACanvas: TCanvas;
  291.       ARect: TRect; Selected: Boolean);
  292.     procedure ReportMemoryLeakTypeOnShutdownActionExecute(Sender: TObject);
  293.     procedure IgnoreMemoryLeakInSetUpTearDownActionExecute(
  294.       Sender: TObject);
  295.     procedure TestCaseIgnoreSetUpTearDownLeaksMenuItemClick(Sender: TObject);
  296.     procedure TestCaseIgnoreSetUpTearDownLeaksMenuItemDrawItem(Sender: TObject;
  297.       ACanvas: TCanvas; ARect: TRect; Selected: Boolean);
  298.   private
  299.     FNoCheckExecutedPtyOverridden: Boolean;
  300.     FMemLeakDetectedPtyOverridden: Boolean;
  301.     FIgnoreSetUpTearDownLeakPtyOverridden: Boolean;
  302.     FPopupY: Integer;
  303.     FPopupX: Integer;
  304.     procedure ResetProgress;
  305.     procedure MenuLooksInactive(ACanvas: TCanvas; ARect: TRect; Selected: Boolean;
  306.       ATitle: string; TitlePosn: UINT; PtyOveridesGUI: boolean);
  307.     procedure MenuLooksActive(ACanvas: TCanvas; ARect: TRect; Selected: Boolean;
  308.       ATitle: string; TitlePosn: UINT);
  309.     function  GetPropertyName(const Caption: string): string;
  310.   protected
  311.     FSuite:         ITest;
  312.     FTestResult:    TTestResult;
  313.     FRunning:       Boolean;
  314.     FTests:         TInterfaceList;
  315.     FSelectedTests: TInterfaceList;
  316.     FTotalTime:     Int64;
  317.     FRunTimeStr:    string;
  318.     FNoChecksStr:   string;
  319.     FMemLeakStr:    string;
  320.     FMemGainStr:    string;
  321.     FMemBytesStr:   string;
  322.     FIgnoreLeakStr: string;
  323.     FBytes:         string;
  324.     FErrorCount:    Integer;
  325.     FFailureCount:  Integer;
  326.     FStrMaxLen:     Integer;
  327.     FValMaxLen:     Integer;
  328.     FUpdateTimer:   TTimer;
  329.     FTimerExpired:  Boolean;
  330.     FTotalTestsCount: Integer;
  331.     procedure Setup;
  332.     procedure SetUpStateImages;
  333.     procedure SetSuite(value: ITest);
  334.     procedure ClearResult;
  335.     procedure DisplayFailureMessage(Item :TListItem);
  336.     procedure ClearFailureMessage;
  337.     function  AddFailureItem(failure: TTestFailure): TListItem;
  338.     procedure UpdateStatus(const fullUpdate:Boolean);
  339.     procedure FillTestTree(RootNode: TTreeNode; ATest: ITest); overload;
  340.     procedure FillTestTree(ATest: ITest);                      overload;
  341.     procedure UpdateNodeImage(node: TTreeNode);
  342.     procedure UpdateNodeState(node: TTreeNode);
  343.     procedure SetNodeState(node: TTreeNode; enabled :boolean);
  344.     procedure SwitchNodeState(node: TTreeNode);
  345.     procedure UpdateTestTreeState;
  346.     procedure MakeNodeVisible(node :TTreeNode);
  347.     procedure SetTreeNodeImage(Node :TTReeNode; imgIndex :Integer);
  348.     procedure SelectNode(node: TTreeNode);
  349.     function  NodeToTest(node :TTreeNode) :ITest;
  350.     function  TestToNode(test :ITest) :TTreeNode;
  351.     function  SelectedTest :ITest;
  352.     procedure ListSelectedTests;
  353.     function  EnableTest(test :ITest) : boolean;
  354.     function  DisableTest(test :ITest) : boolean;
  355.     procedure ApplyToTests(root :TTreeNode; const func :TTestFunc);
  356.     procedure EnableUI(enable :Boolean);
  357.     procedure RunTheTest(aTest: ITest);
  358.     procedure InitTree; virtual;
  359.     function  IniFileName :string;
  360.     function  GetIniFile( const FileName : string ) : tCustomIniFile;
  361.     procedure LoadRegistryAction;
  362.     procedure SaveRegistryAction;
  363.     procedure LoadFormPlacement;
  364.     procedure SaveFormPlacement;
  365.     procedure SaveConfiguration;
  366.     procedure LoadConfiguration;
  367.     procedure LoadSuiteConfiguration;
  368.     procedure AutoSaveConfiguration;
  369.     function NodeIsGrandparent(ANode: TTreeNode): boolean;
  370.     procedure CollapseNonGrandparentNodes(RootNode: TTreeNode);
  371.     procedure ProcessClickOnStateIcon;
  372.     procedure ClearStatusMessage;
  373.     procedure CopyTestNametoClipboard(ANode: TTreeNode);
  374.     procedure SetupCustomShortcuts;
  375.     procedure SetupGUINodes;
  376.     function SelectNodeIfTestEnabled(ANode: TTreeNode): boolean;
  377.     procedure OnUpdateTimer(Sender: TObject);
  378.   public
  379.     {: implement the ITestListener interface }
  380.     procedure AddSuccess(test: ITest);
  381.     procedure AddError(failure: TTestFailure);
  382.     procedure AddFailure(failure: TTestFailure);
  383.     function  ShouldRunTest(test :ITest):boolean;
  384.     procedure StartSuite(suite: ITest); virtual;
  385.     procedure EndSuite(suite: ITest); virtual;
  386.     procedure StartTest(test: ITest); virtual;
  387.     procedure EndTest(test: ITest); virtual;
  388.     procedure TestingStarts;
  389.     procedure TestingEnds(TestResult :TTestResult);
  390.     procedure Status(test :ITest; const Msg :string);
  391.     procedure Warning(test :ITest; const Msg :string);
  392.     {: The number of errors in the last test run }
  393.     property ErrorCount: Integer read FErrorCount;
  394.     {: The number of failures in the last test run }
  395.     property FailureCount: Integer read FFailureCount;
  396.     {: The test suite to be run in this runner }
  397.     property Suite: ITest read FSuite write SetSuite;
  398.     {: The result of the last test run }
  399.     property TestResult : TTestResult read FTestResult write FTestResult;
  400.     class procedure RunTest(test: ITest);
  401.     class procedure RunRegisteredTests;
  402.   end;
  403. procedure RunTest(test: ITest);
  404. procedure RunRegisteredTests;
  405. procedure RunTestModeless(test: ITest);
  406. procedure RunRegisteredTestsModeless;
  407. // Run all tests in unattended mode, i.e. automatically
  408. function RunRegisteredTestsModelessUnattended: Integer;
  409. implementation
  410. uses
  411. {$IFDEF FASTMM}
  412.   {$IFNDEF VER180}
  413.     {$IFNDEF CLR}
  414.       {$IFNDEF ManualLeakReportingControl}
  415.         {$I FastMM4Options.inc}
  416.       {$ENDIF}
  417.       FastMM4,
  418.     {$ENDIF}
  419.   {$ENDIF}
  420. {$ENDIF}
  421.   Registry,
  422.   SysUtils,
  423.   Clipbrd;
  424. {$BOOLEVAL OFF}  // Required or you'll get an AV
  425. {$R *.DFM}
  426. type
  427.   TProgressBarCrack = class(TProgressBar);
  428. procedure RunTest(test: ITest);
  429. begin
  430.   with TGUITestRunner.Create(nil) do
  431.   begin
  432.     try
  433.       Suite := test;
  434.       ShowModal;
  435.     finally
  436.       Free;
  437.     end;
  438.   end;
  439. end;
  440. procedure RunTestModeless(test: ITest);
  441. var
  442.   GUI :TGUITestRunner;
  443. begin
  444.   Application.CreateForm(TGUITestRunner, GUI);
  445.   GUI.Suite := test;
  446.   GUI.Show;
  447. end;
  448. procedure RunRegisteredTests;
  449. begin
  450.    RunTest(registeredTests)
  451. end;
  452. procedure RunRegisteredTestsModeless;
  453. begin
  454.    RunTestModeless(registeredTests)
  455. end;
  456. // Run all tests in unattended mode, i.e. automatically
  457. function RunRegisteredTestsModelessUnattended: Integer;
  458. var
  459.   GUI :TGUITestRunner;
  460. begin
  461.   // Create and show the GUI runner form
  462.   Application.CreateForm(TGUITestRunner, GUI);
  463.   GUI.Suite := registeredTests;
  464.   GUI.Show;
  465.   GUI.RunActionExecute(GUI.RunItem);
  466.   // Process messages until the tests have finished
  467.   repeat
  468.     try
  469.       Application.HandleMessage;
  470.     except
  471.       Application.HandleException(Application);
  472.     end;
  473.   until TGUITestRunner(Application.MainForm).RunAction.Enabled;
  474.   // Return the number of errors and failures and free the runner form
  475.   Result := GUI.ErrorCount + GUI.FailureCount;
  476.   GUI.Free;
  477. end;
  478. { TGUITestRunner }
  479. procedure TGUITestRunner.InitTree;
  480. begin
  481.   FTests.Clear;
  482.   FillTestTree(Suite);
  483.   Setup;
  484.   if HideTestNodesOnOpenAction.Checked then
  485.     HideTestNodesAction.Execute
  486.   else
  487.     ExpandAllNodesAction.Execute;
  488.   TestTree.Selected := TestTree.Items.GetFirstNode;
  489. end;
  490. function TGUITestRunner.NodeToTest(Node: TTreeNode): ITest;
  491. var
  492.   idx: Integer;
  493. begin
  494.   assert(assigned(Node));
  495.   idx  := Integer(Node.data);
  496.   assert((idx >= 0) and (idx < FTests.Count));
  497.   result := FTests[idx] as ITest;
  498. end;
  499. procedure TGUITestRunner.OnUpdateTimer(Sender: TObject);
  500. begin
  501.   FTimerExpired := True;
  502.   FUpdateTimer.Enabled := False;
  503. end;
  504. function TGUITestRunner.TestToNode(test: ITest): TTreeNode;
  505. begin
  506.   assert(assigned(test));
  507.   Result := test.GUIObject as TTreeNode;
  508.   assert(assigned(Result));
  509. end;
  510. function TGUITestRunner.ShouldRunTest(test: ITest): boolean;
  511. begin
  512.   if FSelectedTests = nil then
  513.     Result := test.Enabled
  514.   else
  515.     Result := FSelectedTests.IndexOf(test as ITest) >= 0;
  516. end;
  517. procedure TGUITestRunner.StartTest(test: ITest);
  518. var
  519.   node :TTreeNode;
  520. begin
  521.   assert(assigned(TestResult));
  522.   assert(assigned(test));
  523.   node := TestToNode(test);
  524.   assert(assigned(node));
  525.   SetTreeNodeImage(node, imgRunning);
  526.   if ShowTestedNodeAction.Checked then
  527.   begin
  528.     MakeNodeVisible(node);
  529.     TestTree.Update;
  530.   end;
  531.   ClearStatusMessage;
  532.   UpdateStatus(False);
  533. end;
  534. procedure TGUITestRunner.EndTest(test: ITest);
  535. begin
  536.   UpdateStatus(False);
  537. end;
  538. procedure TGUITestRunner.TestingStarts;
  539. begin
  540.   FTotalTime := 0;
  541.   UpdateStatus(True);
  542.   TProgressBarCrack(ScoreBar).Color := clOK;
  543.   TProgressBarCrack(ScoreBar).RecreateWnd;
  544. end;
  545. procedure TGUITestRunner.AddSuccess(test: ITest);
  546. var
  547.   OverridesGUI: Boolean;
  548.   HasRunTimePropsSet: Boolean;
  549. begin
  550.   assert(assigned(test));
  551.   if not IsTestMethod(test) then
  552.     SetTreeNodeImage(TestToNode(Test), imgRun)
  553.   else
  554.   begin
  555.     OverridesGUI :=
  556.       ((FailIfNoChecksExecuted.Checked and not Test.FailsOnNoChecksExecuted) or
  557.        (FailTestCaseIfMemoryLeaked.Checked and not Test.FailsOnMemoryLeak)) or
  558.        (FailTestCaseIfMemoryLeaked.Checked and Test.IgnoreSetUpTearDownLeaks and
  559.          not IgnoreMemoryLeakInSetUpTearDown.Checked);
  560.     HasRunTimePropsSet :=
  561.       ((Test.FailsOnNoChecksExecuted and not FailIfNoChecksExecuted.Checked) or
  562.        (Test.FailsOnMemoryLeak and not FailTestCaseIfMemoryLeaked.Checked) or
  563.        (FailTestCaseIfMemoryLeaked.Checked and Test.IgnoreSetUpTearDownLeaks) or
  564.        (Test.AllowedMemoryLeakSize <> 0));
  565.     if OverridesGUI then
  566.       FTestResult.Overrides := FTestResult.Overrides + 1;
  567.     if (WarnOnFailTestOverride.Checked and OverridesGUI) or
  568.        (ShowTestCaseswithRunTimeProperties.Checked and HasRunTimePropsSet) then
  569.       SetTreeNodeImage(TestToNode(Test), imgHASPROPS)
  570.     else
  571.       SetTreeNodeImage(TestToNode(Test), imgRun);
  572.   end;
  573. end;
  574. procedure TGUITestRunner.AddError(failure: TTestFailure);
  575. var
  576.   ListItem: TListItem;
  577. begin
  578.   ListItem := AddFailureItem(failure);
  579.   ListItem.ImageIndex := imgERROR;
  580.   TProgressBarCrack(ScoreBar).Color := clERROR;
  581.   TProgressBarCrack(ScoreBar).RecreateWnd;
  582.   SetTreeNodeImage(TestToNode(failure.failedTest), imgERROR);
  583.   UpdateStatus(False);
  584. end;
  585. procedure TGUITestRunner.AddFailure(failure: TTestFailure);
  586. var
  587.   ListItem: TListItem;
  588. begin
  589.   ListItem := AddFailureItem(failure);
  590.   ListItem.ImageIndex := imgFAILED;
  591.   if TestResult.errorCount = 0 then
  592.   begin
  593.     TProgressBarCrack(ScoreBar).Color := clFAILURE;
  594.     TProgressBarCrack(ScoreBar).RecreateWnd;
  595.   end;
  596.   SetTreeNodeImage(TestToNode(failure.failedTest), imgFAILED);
  597.   UpdateStatus(False);
  598. end;
  599. function TGUITestRunner.IniFileName: string;
  600. const
  601.   TEST_INI_FILE = 'dunit.ini';
  602. begin
  603.     result := ExtractFilePath(Application.ExeName) + TEST_INI_FILE
  604. end;
  605. procedure TGUITestRunner.LoadFormPlacement;
  606. begin
  607.   with GetIniFile( IniFileName ) do
  608.   try
  609.     Self.SetBounds(
  610.                    ReadInteger(cnConfigIniSection, 'Left',   Left),
  611.                    ReadInteger(cnConfigIniSection, 'Top',    Top),
  612.                    ReadInteger(cnConfigIniSection, 'Width',  Width),
  613.                    ReadInteger(cnConfigIniSection, 'Height', Height)
  614.                    );
  615.     if ReadBool(cnConfigIniSection, 'Maximized', False ) then
  616.       WindowState := wsMaximized;
  617.   finally
  618.     Free;
  619.   end;
  620. end;
  621. procedure TGUITestRunner.SaveFormPlacement;
  622. begin
  623.   with GetIniFile(IniFileName) do
  624.     try
  625.       WriteBool(cnConfigIniSection, 'AutoSave', AutoSaveAction.Checked);
  626.       if WindowState <> wsMaximized then
  627.       begin
  628.         WriteInteger(cnConfigIniSection, 'Left',   Left);
  629.         WriteInteger(cnConfigIniSection, 'Top',    Top);
  630.         WriteInteger(cnConfigIniSection, 'Width',  Width);
  631.         WriteInteger(cnConfigIniSection, 'Height', Height );
  632.       end;
  633.       WriteBool(cnConfigIniSection, 'Maximized', WindowState = wsMaximized );
  634.     finally
  635.       Free
  636.     end;
  637. end;
  638. procedure TGUITestRunner.LoadConfiguration;
  639. var
  640.   i :Integer;
  641. begin
  642.   LoadRegistryAction;
  643.   LoadFormPlacement;
  644.   LoadSuiteConfiguration;
  645.   with GetIniFile(IniFileName) do
  646.   try
  647.     with AutoSaveAction do
  648.       Checked := ReadBool(cnConfigIniSection, 'AutoSave', Checked);
  649.     { center splitter location }
  650.     with ResultsPanel do
  651.       Height := ReadInteger(cnConfigIniSection, 'ResultsPanel.Height', Height);
  652.     { error splitter location }
  653.     with ErrorBoxPanel do
  654.       Height := ReadInteger(cnConfigIniSection, 'ErrorMessage.Height', Height);
  655.     with ErrorBoxVisibleAction do
  656.       Checked := ReadBool(cnConfigIniSection, 'ErrorMessage.Visible', Checked);
  657.     ErrorBoxSplitter.Visible := ErrorBoxVisibleAction.Checked;
  658.     ErrorBoxPanel.Visible    := ErrorBoxVisibleAction.Checked;
  659.     { failure list configuration }
  660.     with FailureListView do begin
  661.       for i := 0 to Columns.Count-1 do
  662.       begin
  663.         Columns[i].Width := Max(4, ReadInteger(cnConfigIniSection,
  664.                                         Format('FailureList.ColumnWidth[%d]', [i]),
  665.                                         Columns[i].Width)
  666.                                         );
  667.       end;
  668.     end;
  669.     { other options }
  670.     HideTestNodesOnOpenAction.Checked := ReadBool(cnConfigIniSection,
  671.       'HideTestNodesOnOpen', HideTestNodesOnOpenAction.Checked);
  672.     BreakOnFailuresAction.Checked := ReadBool(cnConfigIniSection,
  673.       'BreakOnFailures', BreakOnFailuresAction.Checked);
  674.     FailIfNoChecksExecutedAction.Checked := ReadBool(cnConfigIniSection,
  675.       'FailOnNoChecksExecuted', FailIfNoChecksExecutedAction.Checked);
  676.     FailTestCaseIfMemoryLeakedAction.Checked := ReadBool(cnConfigIniSection,
  677.       'FailOnMemoryLeaked', FailTestCaseIfMemoryLeakedAction.Checked);
  678.     IgnoreMemoryLeakInSetUpTearDownAction.Checked := ReadBool(cnConfigIniSection,
  679.       'IgnoreSetUpTearDownLeaks', IgnoreMemoryLeakInSetUpTearDownAction.Checked);
  680.     ReportMemoryLeakTypeOnShutdownAction.Checked := ReadBool(cnConfigIniSection,
  681.       'ReportMemoryLeakTypes', ReportMemoryLeakTypeOnShutdownAction.Checked);
  682.     WarnOnFailTestOverrideAction.Checked := ReadBool(cnConfigIniSection,
  683.       'WarnOnFailTestOverride', WarnOnFailTestOverrideAction.Checked);
  684.     ShowTestedNodeAction.Checked := ReadBool(cnConfigIniSection,
  685.       'SelectTestedNode', ShowTestedNodeAction.Checked);
  686.     FPopupX := ReadInteger(cnConfigIniSection,'PopupX', 350);
  687.     FPopupY := ReadInteger(cnConfigIniSection,'PopupY', 30);
  688.   finally
  689.     Free;
  690.   end;
  691.   if Suite <> nil then
  692.     UpdateTestTreeState;
  693. end;
  694. procedure TGUITestRunner.AutoSaveConfiguration;
  695. begin
  696.   if AutoSaveAction.Checked then
  697.     SaveConfiguration;
  698. end;
  699. procedure TGUITestRunner.SaveConfiguration;
  700. var
  701.   i :Integer;
  702. begin
  703.   if Suite <> nil then
  704.     Suite.SaveConfiguration(IniFileName, UseRegistryAction.Checked, True);
  705.   SaveFormPlacement;
  706.   SaveRegistryAction;
  707.   with GetIniFile(IniFileName) do
  708.   try
  709.     { center splitter location }
  710.     WriteInteger(cnConfigIniSection, 'ResultsPanel.Height',
  711.       ResultsPanel.Height);
  712.     { error box }
  713.     WriteInteger(cnConfigIniSection, 'ErrorMessage.Height',
  714.       ErrorBoxPanel.Height);
  715.     WriteBool(cnConfigIniSection, 'ErrorMessage.Visible',
  716.       ErrorBoxVisibleAction.Checked);
  717.     { failure list configuration }
  718.     with FailureListView do begin
  719.       for i := 0 to Columns.Count-1 do
  720.       begin
  721.        WriteInteger( cnConfigIniSection,
  722.                      Format('FailureList.ColumnWidth[%d]', [i]),
  723.                      Columns[i].Width);
  724.       end;
  725.     end;
  726.     { other options }
  727.     WriteBool(cnConfigIniSection, 'HideTestNodesOnOpen',      HideTestNodesOnOpenAction.Checked);
  728.     WriteBool(cnConfigIniSection, 'BreakOnFailures',          BreakOnFailuresAction.Checked);
  729.     WriteBool(cnConfigIniSection, 'FailOnNoChecksExecuted',   FailIfNoChecksExecutedAction.Checked);
  730.     WriteBool(cnConfigIniSection, 'FailOnMemoryLeaked',       FailTestCaseIfMemoryLeakedAction.Checked);
  731.     WriteBool(cnConfigIniSection, 'IgnoreSetUpTearDownLeaks', IgnoreMemoryLeakInSetUpTearDownAction.Checked);
  732.     WriteBool(cnConfigIniSection, 'ReportMemoryLeakTypes',    ReportMemoryLeakTypeOnShutdownAction.Checked);
  733.     WriteBool(cnConfigIniSection, 'SelectTestedNode',         ShowTestedNodeAction.Checked);
  734.     WriteBool(cnConfigIniSection, 'WarnOnFailTestOverride',   WarnOnFailTestOverrideAction.Checked);
  735.     WriteInteger(cnConfigIniSection, 'PopupX',                FPopupX);
  736.     WriteInteger(cnConfigIniSection, 'PopupY',                FPopupY);
  737.   finally
  738.     Free;
  739.   end;
  740. end;
  741. procedure TGUITestRunner.TestingEnds(TestResult :TTestResult);
  742. begin
  743.   FTotalTime := TestResult.TotalTime;
  744. end;
  745. procedure TGUITestRunner.UpdateNodeState(node: TTreeNode);
  746. var
  747.   test: ITest;
  748. begin
  749.   assert(assigned(node));
  750.   test := NodeToTest(node);
  751.   assert(assigned(test));
  752.   UpdateNodeImage(node);
  753.   if node.HasChildren then
  754.   begin
  755.     node := node.getFirstChild;
  756.     while node <> nil do
  757.     begin
  758.       UpdateNodeState(node);
  759.       node := node.getNextSibling;
  760.     end;
  761.   end;
  762. end;
  763. procedure TGUITestRunner.SetNodeState(node: TTreeNode; enabled :boolean);
  764. var
  765.   MostSeniorChanged :TTReeNode;
  766. begin
  767.    assert(node <> nil);
  768.    // update ancestors if enabling
  769.    NodeToTest(Node).Enabled := enabled;
  770.    MostSeniorChanged := Node;
  771.    if enabled then
  772.    begin
  773.      while Node.Parent <> nil do
  774.      begin
  775.        Node := Node.Parent;
  776.        if not NodeToTest(Node).Enabled then
  777.        begin // changed
  778.           NodeToTest(Node).Enabled := true;
  779.           MostSeniorChanged := Node;
  780.           UpdateNodeImage(Node);
  781.        end
  782.      end;
  783.    end;
  784.    TestTree.Items.BeginUpdate;
  785.    try
  786.      UpdateNodeState(MostSeniorChanged);
  787.    finally
  788.      TestTree.Items.EndUpdate;
  789.    end
  790. end;
  791. procedure TGUITestRunner.SwitchNodeState(node: TTreeNode);
  792. begin
  793.    assert(node <> nil);
  794.    SetNodeState(node, not NodeToTest(node).enabled);
  795. end;
  796. procedure TGUITestRunner.UpdateTestTreeState;
  797. var
  798.   node :TTreeNode;
  799. begin
  800.   if TestTree.Items.Count > 0 then
  801.   begin
  802.     TestTree.Items.BeginUpdate;
  803.     try
  804.       node := TestTree.Items.GetFirstNode;
  805.       while node <> nil do
  806.       begin
  807.         UpdateNodeState(node);
  808.         node := node.getNextSibling;
  809.       end
  810.     finally
  811.       TestTree.Items.EndUpdate;
  812.     end;
  813.   end;
  814. end;
  815. procedure TGUITestRunner.UpdateStatus(const fullUpdate:Boolean);
  816. var
  817.   i :Integer;
  818.   TestNumber: Integer;
  819.    function FormatElapsedTime(milli: Int64):string;
  820.    var
  821.      h,nn,ss,zzz: Cardinal;
  822.    begin
  823.      h := milli div 3600000;
  824.      milli := milli mod 3600000;
  825.      nn := milli div 60000;
  826.      milli := milli mod 60000;
  827.      ss := milli div 1000;
  828.      milli := milli mod 1000;
  829.      zzz := milli;
  830.      Result := Format('%d:%2.2d:%2.2d.%3.3d', [h, nn, ss, zzz]);
  831.    end;
  832. begin
  833.   if ResultsView.Items.Count = 0 then
  834.     Exit;
  835.   if fullUpdate then
  836.   begin
  837.     FTotalTestsCount := Suite.countEnabledTestCases;
  838.     if Assigned(Suite) then
  839.       ResultsView.Items[0].SubItems[0] := IntToStr(FTotalTestsCount)
  840.     else
  841.       ResultsView.Items[0].SubItems[0] := '';
  842.   end;
  843.   
  844.   if TestResult <> nil then
  845.   begin
  846.     // Save the test number as we use it a lot
  847.     TestNumber := TestResult.runCount;
  848.     if fullUpdate or FTimerExpired or ((TestNumber and 15) = 0) then
  849.     begin
  850.       with ResultsView.Items[0] do
  851.       begin
  852.         SubItems[1] := IntToStr(TestNumber);
  853.         SubItems[2] := IntToStr(TestResult.failureCount);
  854.         SubItems[3] := IntToStr(TestResult.errorCount);
  855.         SubItems[4] := IntToStr(TestResult.Overrides);
  856.         SubItems[5] := FormatElapsedTime(TestResult.TotalTime);
  857.         SubItems[6] := FormatElapsedTime(max(TestResult.TotalTime, FTotalTime));
  858.       end;
  859.       with TestResult do
  860.       begin
  861.         ScoreBar.Position  := TestNumber - (failureCount + errorCount);
  862.         ProgressBar.Position := TestNumber;
  863.         // There is a possibility for zero tests
  864.         if (TestNumber = 0) and (Suite.CountEnabledTestCases = 0) then
  865.           LbProgress.Caption := '100%'
  866.         else
  867.           LbProgress.Caption := IntToStr((100 * ScoreBar.Position) div ScoreBar.Max) + '%';
  868.       end;
  869.       if FTimerExpired and (TestNumber < FTotalTestsCount) then
  870.       begin
  871.         FTimerExpired := False;
  872.         FUpdateTimer.Enabled := True;
  873.       end;
  874.     end;
  875.     // Allow just the results pane to catch up
  876.     ResultsPanel.Update;
  877.   end
  878.   else
  879.   begin
  880.     with ResultsView.Items[0] do
  881.     begin
  882.       if (SubItems[0] = '0') or (subItems[0] = '') then
  883.       begin
  884.         for i := 1 to 6 do
  885.           SubItems[i] := ''
  886.       end
  887.       else
  888.       begin
  889.         if SubItems[0] <> subItems[1] then
  890.           for i := 1 to 6 do
  891.             SubItems[i] := ''
  892.         else
  893.         begin
  894.           SubItems[5] := FormatElapsedTime(SelectedTest.ElapsedTestTime);
  895.           SubItems[6] := FormatElapsedTime(Max(SelectedTest.ElapsedTestTime, FTotalTime));
  896.         end;
  897.       end;
  898.     end;
  899.     ResetProgress;
  900.   end;
  901.   if fullUpdate then
  902.   begin
  903.     // Allow the whole display to catch up and check for key strokes
  904.     Update;
  905.     Application.ProcessMessages;
  906.   end;
  907. end;
  908. procedure TGUITestRunner.ResetProgress;
  909. begin
  910.   TProgressBarCrack(ScoreBar).ParentColor := True;
  911.   TProgressBarCrack(ScoreBar).RecreateWnd;
  912.   ScoreBar.Position := 0;
  913.   ProgressBar.Position := 0;
  914.   LbProgress.Caption := '';
  915. end;
  916. function TGUITestRunner.AddFailureItem(failure: TTestFailure): TListItem;
  917. var
  918.   item : TListItem;
  919.   node : TTreeNode;
  920. begin
  921.   assert(assigned(failure));
  922.   item := FailureListView.Items.Add;
  923.   item.data := Pointer(TestToNode(failure.failedTest));
  924.   item.Caption := failure.failedTest.Name;
  925.   item.SubItems.Add(failure.thrownExceptionName);
  926.   item.SubItems.Add(failure.thrownExceptionMessage);
  927.   item.SubItems.Add( failure.LocationInfo
  928.                      + ' ' +
  929.                      failure.AddressInfo
  930.                      );
  931.   item.SubItems.Add(failure.StackTrace);
  932.   node := testToNode(failure.failedTest);
  933.   while node <> nil do
  934.   begin
  935.     node.Expand(false);
  936.     node := node.Parent;
  937.   end;
  938.   Result := item;
  939. end;
  940. procedure TGUITestRunner.FillTestTree(RootNode: TTreeNode; ATest: ITest);
  941. var
  942.   TestTests: IInterfaceList;
  943.   i: Integer;
  944. begin
  945.   if ATest = nil then
  946.     EXIT;
  947.   RootNode := TestTree.Items.AddChild(RootNode, ATest.Name);
  948.   RootNode.data := TObject(FTests.Add(ATest));
  949.   TestTests := ATest.Tests;
  950.   for i := 0 to TestTests.count - 1 do
  951.   begin
  952.     FillTestTree(RootNode, TestTests[i] as ITest);
  953.   end;
  954. end;
  955. procedure TGUITestRunner.FillTestTree(ATest: ITest);
  956. begin
  957.   TestTree.Items.Clear;
  958.   FTests.Clear;
  959.   fillTestTree(nil, Suite);
  960. end;
  961. procedure TGUITestRunner.SetTreeNodeImage(Node :TTReeNode; imgIndex :Integer);
  962. begin
  963.   while Node <> nil do
  964.   begin
  965.     if imgIndex > Node.ImageIndex then
  966.     begin
  967.        Node.ImageIndex    := imgIndex;
  968.        Node.SelectedIndex := imgIndex;
  969.     end;
  970.     if imgIndex = imgRunning then
  971.       Node := nil
  972.     else
  973.       Node := Node.Parent;
  974.   end;
  975. end;
  976. procedure TGUITestRunner.SetSuite(value: ITest);
  977. begin
  978.   FSuite := value;
  979.   if FSuite <> nil then
  980.   begin
  981.     LoadSuiteConfiguration;
  982.     EnableUI(True);
  983.     InitTree;
  984.   end
  985.   else
  986.     EnableUI(False)
  987. end;
  988. procedure TGUITestRunner.DisplayFailureMessage(Item: TListItem);
  989. var
  990.   hlColor :TColor;
  991.   Test    :ITest;
  992.   Status  :string;
  993. begin
  994.   TestTree.Selected := TTreeNode(Item.data);
  995.   Test := NodeToTest(TestTree.Selected);
  996.   hlColor := clFAILURE;
  997.   if Item.ImageIndex >= imgERROR then
  998.      hlColor := clERROR;
  999.   with ErrorMessageRTF do
  1000.     begin
  1001.       Clear;
  1002.       SelAttributes.Size  := self.Font.Size;
  1003.       SelAttributes.Style := [fsBold];
  1004.       SelText := Item.Caption + ': ';
  1005.       SelAttributes.Color := hlColor;
  1006.       SelAttributes.Style := [fsBold];
  1007.       SelText := Item.SubItems[0];
  1008.       Lines.Add('');
  1009.       SelAttributes.Color := clWindowText;
  1010.       SelAttributes.Style := [];
  1011.       SelText := 'at ' + Item.SubItems[2];
  1012.       if Item.SubItems[1] <> '' then
  1013.       begin
  1014.         SelAttributes.Color := clWindowText;
  1015.         Lines.Add('');
  1016.         SelAttributes.Size  := 12;
  1017.         SelAttributes.Style := [];
  1018.         SelText := Item.SubItems[1];
  1019.         SelAttributes.Size  := self.Font.Size;
  1020.       end;
  1021.       Status := Test.Status;
  1022.       if Status <> '' then
  1023.       begin
  1024.         Lines.Add('');
  1025.         Lines.Add('');
  1026.         SelAttributes.Style := [fsBold];
  1027.         Lines.Add('Status Messages');
  1028.         SelAttributes.Style := [];
  1029.         Lines.Add(Status);
  1030.       end;
  1031.       if Item.SubItems[3] <> '' then
  1032.       begin
  1033.         Lines.Add('');
  1034.         SelAttributes.Style := [fsBold];
  1035.         Lines.Add('StackTrace');
  1036.         SelAttributes.Style := [];
  1037.         SelText := Item.SubItems[3];
  1038.       end;
  1039.     end
  1040. end;
  1041. procedure TGUITestRunner.ClearFailureMessage;
  1042. begin
  1043.   ErrorMessageRTF.Clear;
  1044. end;
  1045. procedure TGUITestRunner.ClearResult;
  1046. begin
  1047.   if FTestResult <> nil then
  1048.   begin
  1049.     FTestResult.Free;
  1050.     FTestResult := nil;
  1051.     ClearFailureMessage;
  1052.   end;
  1053. end;
  1054. procedure TGUITestRunner.SetUp;
  1055. var
  1056.   i: Integer;
  1057.   node: TTreeNode;
  1058. begin
  1059.   FailureListView.Items.Clear;
  1060.   ResetProgress;
  1061.   Update;
  1062.   with ResultsView.Items[0] do
  1063.   begin
  1064.     if Suite <> nil then
  1065.     begin
  1066.       i := Suite.countEnabledTestCases;
  1067.       SubItems[0] := IntToStr(i);
  1068.       ProgressBar.Max := i
  1069.     end
  1070.     else
  1071.     begin
  1072.       SubItems[0] := '';
  1073.       ProgressBar.Max:= 10000;
  1074.     end;
  1075.     ScoreBar.Max := ProgressBar.Max;
  1076.     SubItems[1] := '';
  1077.     SubItems[2] := '';
  1078.     SubItems[3] := '';
  1079.     SubItems[4] := '';
  1080.     SubItems[5] := '';
  1081.     SubItems[6] := '';
  1082.   end;
  1083.   for i := 0 to TestTree.Items.Count - 1 do
  1084.   begin
  1085.     node := TestTree.Items[i];
  1086.     node.ImageIndex    := imgNONE;
  1087.     node.SelectedIndex := imgNONE;
  1088.   end;
  1089.   UpdateTestTreeState;
  1090. end;
  1091. procedure TGUITestRunner.EnableUI(enable: Boolean);
  1092. begin
  1093.   SelectAllAction.Enabled    := enable;
  1094.   DeselectAllAction.Enabled  := enable;
  1095.   SelectFailedAction.Enabled := enable;
  1096.   SelectCurrentAction.Enabled := enable;
  1097.   DeselectCurrentAction.Enabled := enable;
  1098.   HideTestNodesAction.Enabled   := enable;
  1099.   ExpandAllNodesAction.Enabled  := enable;
  1100. end;
  1101. procedure TGUITestRunner.FormCreate(Sender: TObject);
  1102. begin
  1103.   inherited;
  1104.   FTests := TInterfaceList.Create;
  1105.   LoadConfiguration;
  1106.   TimeSeparator := ':';
  1107.   SetUpStateImages;
  1108.   SetupCustomShortcuts;
  1109.   TestTree.Items.Clear;
  1110.   EnableUI(false);
  1111.   ClearFailureMessage;
  1112.   FUpdateTimer := TTimer.Create(Self);
  1113.   FUpdateTimer.Interval := 200;
  1114.   FUpdateTimer.Enabled := False;
  1115.   FUpdateTimer.OnTimer := OnUpdateTimer;
  1116.   Setup;
  1117.   {$IFDEF VER180} //FastMM built in already
  1118.     FailTestCaseIfMemoryLeakedAction.Enabled := True;
  1119.     ReportMemoryLeaksOnShutdown := ReportMemoryLeakTypeOnShutdownAction.Checked;
  1120.   {$ELSE}
  1121.     {$IFDEF FASTMM}
  1122.       FailTestCaseIfMemoryLeakedAction.Enabled := True;
  1123.       {$IFDEF ManualLeakReportingControl}
  1124.         ReportMemoryLeaksOnShutdown := ReportMemoryLeakTypeOnShutdownAction.Checked;
  1125.       {$ELSE}
  1126.         ReportMemoryLeakTypeOnShutdownAction.Checked := False;
  1127.         ReportMemoryLeakTypeOnShutdownAction.Enabled := False;
  1128.       {$ENDIF}
  1129.     {$ELSE}
  1130.       FailTestCaseIfMemoryLeakedAction.Enabled := False;
  1131.       ReportMemoryLeakTypeOnShutdownAction.Checked := False;
  1132.       ReportMemoryLeakTypeOnShutdownAction.Enabled := False;
  1133.     {$ENDIF}
  1134.   {$ENDIF}
  1135.   if not FailTestCaseIfMemoryLeakedAction.Enabled then
  1136.     FailTestCaseIfMemoryLeakedAction.Checked := False;
  1137.   IgnoreMemoryLeakInSetUpTearDownAction.Enabled :=
  1138.     FailTestCaseIfMemoryLeakedAction.Checked;
  1139.   if not IgnoreMemoryLeakInSetUpTearDownAction.Enabled then
  1140.     IgnoreMemoryLeakInSetUpTearDownAction.Checked := False;
  1141. end;
  1142. procedure TGUITestRunner.FormDestroy(Sender: TObject);
  1143. begin
  1144.   FreeAndNil(FUpdateTimer);
  1145.   ClearResult;
  1146.   AutoSaveConfiguration;
  1147.   Suite := nil;
  1148.   FTests.Free;
  1149.   FTests := nil;
  1150.   inherited;
  1151. end;
  1152. procedure TGUITestRunner.FormShow(Sender: TObject);
  1153. begin
  1154.   { Set up the GUI nodes in the test nodes. We do it here because the form,
  1155.     the tree and all its tree nodes get recreated in TCustomForm.ShowModal
  1156.     in D8+ so we cannot do it sooner. }
  1157.   SetupGUINodes;
  1158. end;
  1159. procedure TGUITestRunner.TestTreeClick(Sender: TObject);
  1160. begin
  1161.   if FRunning then
  1162.     EXIT;
  1163.   ProcessClickOnStateIcon;
  1164.   TestTreeChange(Sender, TestTree.Selected);
  1165. end;
  1166. procedure TGUITestRunner.TestTreeChange(Sender: TObject; Node: TTreeNode);
  1167. var
  1168.   i : Integer;
  1169. begin
  1170.   if (Node <> nil) and (Node = TestTree.Selected) then
  1171.   begin
  1172.     FailureListView.Selected := nil;
  1173.     for i := 0 to FailureListView.Items.count - 1 do
  1174.     begin
  1175.       if TTreeNode(FailureListView.Items[i].Data) = Node then
  1176.       begin
  1177.         FailureListView.Selected := FailureListView.Items[i];
  1178.         break;
  1179.       end;
  1180.     end;
  1181.     UpdateStatus(True);
  1182.   end;
  1183. end;
  1184. procedure TGUITestRunner.FailureListViewClick(Sender: TObject);
  1185. begin
  1186.   if FailureListView.Selected <> nil then
  1187.   begin
  1188.     TestTree.Selected := TTreeNode(FailureListView.Selected.data);
  1189.   end;
  1190. end;
  1191. procedure TGUITestRunner.FailureListViewSelectItem(Sender: TObject; Item: TListItem; Selected: Boolean);
  1192. begin
  1193.   if not Selected then
  1194.     ClearFailureMessage
  1195.   else
  1196.     DisplayFailureMessage(Item);
  1197. end;
  1198. function TGUITestRunner.DisableTest(test: ITest): boolean;
  1199. begin
  1200.   test.enabled := false;
  1201.   result := true;
  1202. end;
  1203. function TGUITestRunner.EnableTest(test: ITest): boolean;
  1204. begin
  1205.   test.enabled := true;
  1206.   result := true;
  1207. end;
  1208. procedure TGUITestRunner.ApplyToTests(root :TTreeNode; const func :TTestFunc);
  1209.   procedure DoApply(rootnode :TTreeNode);
  1210.   var
  1211.     test: ITest;
  1212.     node: TTreeNode;
  1213.   begin
  1214.     if rootnode <> nil then
  1215.     begin
  1216.       test := NodeToTest(rootnode);
  1217.       if func(test) then
  1218.       begin
  1219.         node := rootnode.getFirstChild;
  1220.         while node <> nil do
  1221.         begin
  1222.           DoApply(node);
  1223.           node := node.getNextSibling;
  1224.         end;
  1225.       end;
  1226.     end;
  1227.   end;
  1228. begin
  1229.   TestTree.Items.BeginUpdate;
  1230.   try
  1231.     DoApply(root)
  1232.   finally
  1233.     TestTree.Items.EndUpdate
  1234.   end;
  1235.   UpdateTestTreeState;
  1236. end;
  1237. procedure TGUITestRunner.TestTreeKeyPress(Sender: TObject; var Key: Char);
  1238. begin
  1239.   if (Key = ' ') and (TestTree.Selected <> nil) then
  1240.   begin
  1241.     SwitchNodeState(TestTree.Selected);
  1242.     UpdateStatus(True);
  1243.     Key := #0
  1244.   end;
  1245. end;
  1246. procedure TGUITestRunner.SelectAllActionExecute(Sender: TObject);
  1247. begin
  1248.   ApplyToTests(TestTree.Items.GetFirstNode, EnableTest);
  1249.   UpdateStatus(True);
  1250. end;
  1251. procedure TGUITestRunner.DeselectAllActionExecute(Sender: TObject);
  1252. begin
  1253.   ApplyToTests(TestTree.Items.GetFirstNode, DisableTest);
  1254.   UpdateStatus(True);
  1255. end;
  1256. procedure TGUITestRunner.SelectFailedActionExecute(Sender: TObject);
  1257. var
  1258.   i: integer;
  1259.   ANode: TTreeNode;
  1260. begin
  1261.   { deselect all }
  1262.   ApplyToTests(TestTree.Items[0], DisableTest);
  1263.   { select failed }
  1264.   for i := 0 to FailureListView.Items.Count - 1 do
  1265.   begin
  1266.     ANode := TTreeNode(FailureListView.Items[i].Data);
  1267.     SetNodeState(ANode, true);
  1268.   end;
  1269.   UpdateStatus(True);
  1270. end;
  1271. procedure TGUITestRunner.SaveConfigurationActionExecute(Sender: TObject);
  1272. begin
  1273.   SaveConfiguration
  1274. end;
  1275. procedure TGUITestRunner.RestoreSavedActionExecute(Sender: TObject);
  1276. begin
  1277.   LoadConfiguration
  1278. end;
  1279. procedure TGUITestRunner.AutoSaveActionExecute(Sender: TObject);
  1280. begin
  1281.   with AutoSaveAction do
  1282.   begin
  1283.     Checked := not Checked
  1284.   end;
  1285.   AutoSaveConfiguration;
  1286. end;
  1287. procedure TGUITestRunner.ErrorBoxVisibleActionExecute(Sender: TObject);
  1288. begin
  1289.    with ErrorBoxVisibleAction do
  1290.    begin
  1291.      Checked := not Checked;
  1292.      ErrorBoxSplitter.Visible := Checked;
  1293.      ErrorBoxPanel.Visible    := Checked;
  1294.      if Checked then
  1295.      begin
  1296.       // Solve bugs with Delphi4 resizing with constraints
  1297.        ErrorBoxSplitter.Top := ErrorBoxPanel.Top-8;
  1298.      end
  1299.    end;
  1300. end;
  1301. procedure TGUITestRunner.ErrorBoxSplitterMoved(Sender: TObject);
  1302. begin
  1303.   // Solve bugs with Delphi4 resizing with constraints
  1304.   ErrorBoxSplitter.Top := ErrorBoxPanel.Top-8;
  1305.   self.Update;
  1306. end;
  1307. procedure TGUITestRunner.ErrorBoxPanelResize(Sender: TObject);
  1308. begin
  1309.   // Solve bugs with Delphi4 resizing with constraints
  1310.   ErrorBoxSplitter.Top := ErrorBoxPanel.Top-8;
  1311. end;
  1312. function TGUITestRunner.NodeIsGrandparent(ANode: TTreeNode): boolean;
  1313. var
  1314.   AChildNode: TTreeNode;
  1315. begin
  1316.   Result := false;
  1317.   if ANode.HasChildren then
  1318.   begin
  1319.     AChildNode := ANode.GetFirstChild;
  1320.     while AChildNode <> nil do
  1321.     begin
  1322.       Result := AChildNode.HasChildren or Result;
  1323.       AChildNode := ANode.GetNextChild(AChildNode);
  1324.     end;
  1325.   end;
  1326. end;
  1327. procedure TGUITestRunner.CollapseNonGrandparentNodes(RootNode: TTreeNode);
  1328. var
  1329.   AChildNode: TTreeNode;
  1330. begin
  1331.   if not NodeIsGrandparent(RootNode) then
  1332.     RootNode.Collapse(false);
  1333.   AChildNode := RootNode.GetFirstChild;
  1334.   while AChildNode <> nil do
  1335.   begin
  1336.     CollapseNonGrandparentNodes(AChildNode);
  1337.     AChildNode := RootNode.GetNextChild(AChildNode);
  1338.   end;
  1339. end;
  1340. procedure TGUITestRunner.HideTestNodesActionExecute(Sender: TObject);
  1341. var
  1342.   ANode: TTreeNode;
  1343. begin
  1344.   inherited;
  1345.   if TestTree.Items.Count = 0 then
  1346.     EXIT;
  1347.   TestTree.Items.BeginUpdate;
  1348.   try
  1349.     ANode := TestTree.Items[0];
  1350.     if ANode <> nil then
  1351.     begin
  1352.       ANode.Expand(true);
  1353.       CollapseNonGrandparentNodes(ANode);
  1354.       SelectNode(ANode);
  1355.     end;
  1356.   finally
  1357.     TestTree.Items.EndUpdate;
  1358.   end;
  1359. end;
  1360. procedure TGUITestRunner.HideTestNodesOnOpenActionExecute(Sender: TObject);
  1361. begin
  1362.   HideTestNodesOnOpenAction.Checked := not HideTestNodesOnOpenAction.Checked;
  1363. end;
  1364. procedure TGUITestRunner.ExpandAllNodesActionExecute(Sender: TObject);
  1365. begin
  1366.   TestTree.FullExpand;
  1367.   if (TestTree.Selected <> nil) then
  1368.     MakeNodeVisible(TestTree.Selected)
  1369.   else if(TestTree.Items.Count > 0) then
  1370.     TestTree.Selected := TestTree.Items[0];
  1371. end;
  1372. procedure TGUITestRunner.RunTheTest(aTest : ITest);
  1373. begin
  1374.   if aTest = nil then
  1375.     EXIT;
  1376.   if FRunning then
  1377.   begin
  1378.     // warning: we're reentering this method if FRunning is true
  1379.     assert(FTestResult <> nil);
  1380.     FTestResult.Stop;
  1381.     EXIT;
  1382.   end;
  1383.   FRunning := true;
  1384.   try
  1385.     RunAction.Enabled  := False;
  1386.     StopAction.Enabled := True;
  1387.     CopyMessageToClipboardAction.Enabled := false;
  1388.     EnableUI(false);
  1389.     AutoSaveConfiguration;
  1390.     ClearResult;
  1391.     TestResult := TTestResult.create;
  1392.     try
  1393.       TestResult.addListener(self);
  1394.       TestResult.BreakOnFailures := BreakOnFailuresAction.Checked;
  1395.       TestResult.FailsIfNoChecksExecuted := FailIfNoChecksExecutedAction.Checked;
  1396.       TestResult.FailsIfMemoryLeaked := FailTestCaseIfMemoryLeakedAction.Checked;
  1397.       TestResult.IgnoresMemoryLeakInSetUpTearDown :=
  1398.         IgnoreMemoryLeakInSetUpTearDownAction.Checked;
  1399.       aTest.run(TestResult);
  1400.     finally
  1401.       FErrorCount := TestResult.ErrorCount;
  1402.       FFailureCount := TestResult.FailureCount;
  1403.       TestResult.Free;
  1404.       TestResult := nil;
  1405.     end;
  1406.   finally
  1407.       FRunning := false;
  1408.       EnableUI(true);
  1409.   end;
  1410. end;
  1411. procedure TGUITestRunner.RunActionExecute(Sender: TObject);
  1412. begin
  1413.   if Suite = nil then
  1414.     EXIT;
  1415.   Setup;
  1416.   RunTheTest(Suite);
  1417. end;
  1418. procedure TGUITestRunner.ExitActionExecute(Sender: TObject);
  1419. begin
  1420.   if FTestResult <> nil then
  1421.      FTestResult.stop;
  1422.   self.ModalResult := mrCancel;
  1423.   Close;
  1424. end;
  1425. procedure TGUITestRunner.BreakOnFailuresActionExecute(Sender: TObject);
  1426. begin
  1427.   with BreakOnFailuresAction do
  1428.    Checked := not Checked;
  1429. end;
  1430. procedure TGUITestRunner.FailIfNoChecksExecutedActionExecute(Sender: TObject);
  1431. begin
  1432.   with FailIfNoChecksExecutedAction do
  1433.     Checked := not Checked;
  1434. end;
  1435. procedure TGUITestRunner.FailTestCaseIfMemoryLeakedActionExecute(Sender: TObject);
  1436. begin
  1437.   with FailTestCaseIfMemoryLeakedAction do
  1438.   begin
  1439.     Checked := not Checked;
  1440.     IgnoreMemoryLeakInSetUpTearDownAction.Enabled := Checked;
  1441.     if not Checked then
  1442.       IgnoreMemoryLeakInSetUpTearDownAction.Checked := False;
  1443.   end;
  1444. end;
  1445. procedure TGUITestRunner.ShowTestCasesWithRunTimePropertiesActionExecute(
  1446.   Sender: TObject);
  1447. begin
  1448.   with ShowTestCasesWithRunTimePropertiesAction do
  1449.   begin
  1450.     Checked := not Checked;
  1451.     if Checked then
  1452.       WarnOnFailTestOverrideAction.Checked := False;
  1453.   end;
  1454. end;
  1455. procedure TGUITestRunner.WarnOnFailTestOverrideActionExecute(
  1456.   Sender: TObject);
  1457. begin
  1458.   with WarnOnFailTestOverrideAction do
  1459.   begin
  1460.     Checked := not Checked;
  1461.     if Checked then
  1462.       ShowTestCasesWithRunTimePropertiesAction.Checked := False;
  1463.   end;
  1464. end;
  1465. procedure TGUITestRunner.ShowTestedNodeActionExecute(Sender: TObject);
  1466. begin
  1467.   with ShowTestedNodeAction do
  1468.     Checked := not Checked;
  1469. end;
  1470. procedure TGUITestRunner.SetUpStateImages;
  1471. begin
  1472.     TestTree.Images             := RunImages;
  1473.     TestTree.StateImages        := StateImages;
  1474.     FailureListView.SmallImages := RunImages;
  1475. end;
  1476. procedure TGUITestRunner.LoadSuiteConfiguration;
  1477. begin
  1478.   if Suite <> nil then
  1479.     Suite.LoadConfiguration(IniFileName, UseRegistryAction.Checked, True);
  1480. end;
  1481. procedure TGUITestRunner.MakeNodeVisible(node: TTreeNode);
  1482. begin
  1483.   node.MakeVisible
  1484. end;
  1485. procedure TGUITestRunner.ProcessClickOnStateIcon;
  1486. var
  1487.   HitInfo: THitTests;
  1488.   node: TTreeNode;
  1489.   PointPos: TPoint;
  1490. begin
  1491.   GetCursorPos(PointPos);
  1492.   PointPos := TestTree.ScreenToClient(PointPos);
  1493.   with PointPos do
  1494.   begin
  1495.     HitInfo := TestTree.GetHitTestInfoAt(X, Y);
  1496.     node := TestTree.GetNodeAt(X, Y);
  1497.   end;
  1498.   if (node <> nil) and (HtOnStateIcon in HitInfo) then
  1499.   begin
  1500.     SwitchNodeState(node);
  1501.   end;
  1502. end;
  1503. procedure TGUITestRunner.UpdateNodeImage(node: TTreeNode);
  1504. var
  1505.   test :ITest;
  1506. begin
  1507.   test := NodeToTest(node);
  1508.   if not test.enabled then
  1509.   begin
  1510.     node.StateIndex := imgDISABLED;
  1511.   end
  1512.   else if (node.Parent <> nil)
  1513.   and (node.Parent.StateIndex <= imgPARENT_DISABLED) then
  1514.   begin
  1515.     node.StateIndex := imgPARENT_DISABLED;
  1516.   end
  1517.   else
  1518.   begin
  1519.     node.StateIndex := imgENABLED;
  1520.   end;
  1521. end;
  1522. procedure TGUITestRunner.CopyMessageToClipboardActionExecute(Sender: TObject);
  1523. begin
  1524.   ErrorMessageRTF.SelectAll;
  1525.   ErrorMessageRTF.CopyToClipboard;
  1526. end;
  1527. procedure TGUITestRunner.UseRegistryActionExecute(Sender: TObject);
  1528. begin
  1529.   with UseRegistryAction do
  1530.     Checked := not Checked;
  1531. end;
  1532. function TGUITestRunner.GetIniFile(const FileName: string) : tCustomIniFile;
  1533. begin
  1534.   if UseRegistryAction.Checked then
  1535.     Result := tRegistryIniFile.Create( GetDUnitRegistryKey + FileName )
  1536.   else
  1537.     Result := tIniFile.Create( FileName );
  1538. end;
  1539. procedure TGUITestRunner.LoadRegistryAction;
  1540. begin
  1541.   with TIniFile.Create(IniFileName) do
  1542.   try
  1543.     UseRegistryAction.Checked := ReadBool(cnConfigIniSection,
  1544.       'UseRegistry', UseRegistryAction.Checked);
  1545.   finally
  1546.     Free;
  1547.   end;
  1548. end;
  1549. procedure TGUITestRunner.SaveRegistryAction;
  1550. begin
  1551.   if UseRegistryAction.Checked then
  1552.     DeleteFile( IniFileName );
  1553.   with TIniFile.Create(IniFileName) do
  1554.   try
  1555.     WriteBool(cnConfigIniSection, 'UseRegistry', UseRegistryAction.Checked);
  1556.   finally
  1557.     Free;
  1558.   end;
  1559. end;
  1560. procedure TGUITestRunner.RunActionUpdate(Sender: TObject);
  1561. begin
  1562.   RunAction.Enabled := not FRunning and assigned( Suite ) and (Suite.countEnabledTestCases > 0);
  1563. end;
  1564. procedure TGUITestRunner.CopyMessageToClipboardActionUpdate(Sender: TObject);
  1565. begin
  1566.   CopyMessageToClipboardAction.Enabled := FailureListView.Selected <> nil;
  1567. end;
  1568. procedure TGUITestRunner.SelectCurrentActionExecute(Sender: TObject);
  1569. begin
  1570.   ApplyToTests(TestTree.Selected, EnableTest);
  1571.   SetNodeState(TestTree.Selected, true);
  1572.   UpdateStatus(True);
  1573. end;
  1574. procedure TGUITestRunner.DeselectCurrentActionExecute(Sender: TObject);
  1575. begin
  1576.   ApplyToTests(TestTree.Selected, DisableTest);
  1577.   UpdateStatus(True);
  1578. end;
  1579. procedure TGUITestRunner.StopActionExecute(Sender: TObject);
  1580. begin
  1581.   if FTestResult <> nil then
  1582.      FTestResult.stop;
  1583. end;
  1584. procedure TGUITestRunner.StopActionUpdate(Sender: TObject);
  1585. begin
  1586.   StopAction.Enabled := FRunning and (FTestResult <> nil);
  1587. end;
  1588. procedure TGUITestRunner.Status(test: ITest; const Msg: string);
  1589. begin
  1590.   if ErrorMessageRTF.Lines.Count = 0 then
  1591.     ErrorMessageRTF.Lines.Add(test.Name + ':');
  1592.   ErrorMessageRTF.Lines.Add(Msg);
  1593.   ErrorMessageRTF.Update;
  1594. end;
  1595. procedure TGUITestRunner.Warning(test: ITest; const Msg: string);
  1596. begin
  1597.   if ErrorMessageRTF.Lines.Count = 0 then
  1598.     ErrorMessageRTF.Lines.Add(test.Name + ':');
  1599.   ErrorMessageRTF.Lines.Add(Msg);
  1600.   ErrorMessageRTF.Update;
  1601. end;
  1602. procedure TGUITestRunner.ClearStatusMessage;
  1603. begin
  1604.   ErrorMessageRTF.Lines.Clear;
  1605. end;
  1606. procedure TGUITestRunner.CopyProcnameToClipboardActionExecute(
  1607.   Sender: TObject);
  1608. begin
  1609.   CopyTestNametoClipboard(TestTree.Selected);
  1610. end;
  1611. procedure TGUITestRunner.CopyTestNametoClipboard(ANode: TTreeNode);
  1612. begin
  1613.   if Assigned(ANode) then
  1614.   begin
  1615.     Clipboard.AsText := ANode.Text;
  1616.   end;
  1617. end;
  1618. procedure TGUITestRunner.CopyProcnameToClipboardActionUpdate(
  1619.   Sender: TObject);
  1620. begin
  1621.   (Sender as TAction).Enabled := Assigned(TestTree.Selected)
  1622.                                  and isTestMethod(NodeToTest(TestTree.Selected));
  1623. end;
  1624. function TGUITestRunner.SelectedTest: ITest;
  1625. begin
  1626.   if TestTree.Selected = nil then
  1627.     Result := nil
  1628.   else
  1629.     Result := NodeToTest(TestTree.Selected);
  1630. end;
  1631. procedure TGUITestRunner.ListSelectedTests;
  1632. var
  1633.   aTest: ITest;
  1634.   aNode: TTreeNode;
  1635. begin
  1636.   FSelectedTests.Free;
  1637.   FSelectedTests := nil;
  1638.   FSelectedTests := TInterfaceList.Create;
  1639.   aNode := TestTree.Selected;
  1640.   while Assigned(aNode) do
  1641.   begin
  1642.     aTest := NodeToTest(aNode);
  1643.     FSelectedTests.Add(aTest as ITest);
  1644.     aNode := aNode.Parent;
  1645.   end;
  1646. end;
  1647. procedure TGUITestRunner.RunSelectedTestActionExecute(Sender: TObject);
  1648. begin
  1649.   Setup;
  1650.   ListSelectedTests;
  1651.   ProgressBar.Max := 1;
  1652.   ScoreBar.Max    := 1;
  1653.   RunTheTest(Suite);
  1654.   {$IFDEF VER130}
  1655.     FreeAndNil(FSelectedTests);
  1656.   {$ELSE}
  1657.     FSelectedTests.Free;
  1658.     FSelectedTests := nil;
  1659.   {$ENDIF}
  1660. end;
  1661. procedure TGUITestRunner.RunSelectedTestActionUpdate(Sender: TObject);
  1662. var
  1663.   aTest :ITest;
  1664. begin
  1665.   ATest := SelectedTest;
  1666.   RunSelectedTestAction.Enabled := (aTest <> nil) and (aTest.CountTestCases = 1);
  1667. end;
  1668. class procedure TGUITestRunner.RunTest(test: ITest);
  1669. var
  1670.   myform: TGUITestRunner;
  1671. begin
  1672.   Application.CreateForm(TGUITestRunner, MyForm);
  1673.   with MyForm do
  1674.   begin
  1675.     try
  1676.       suite := test;
  1677.       ShowModal;
  1678.     finally
  1679.       MyForm.Free;
  1680.     end;
  1681.   end;
  1682. end;
  1683. class procedure TGUITestRunner.RunRegisteredTests;
  1684. begin
  1685.   RunTest(RegisteredTests);
  1686. end;
  1687. procedure TGUITestRunner.EndSuite(suite: ITest);
  1688. begin
  1689.   UpdateStatus(True);
  1690. end;
  1691. procedure TGUITestRunner.StartSuite(suite: ITest);
  1692. begin
  1693. end;
  1694. procedure TGUITestRunner.TestTreeMouseDown(Sender: TObject;
  1695.   Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  1696. var
  1697.   NewNode: TTreeNode;
  1698. begin
  1699.   { a version of this code was in the pmTestTreePopup event, but it created
  1700.     an intermittent bug. OnPopup is executed if any of the ShortCut keys
  1701.     belonging to items on the popup menu are used. This caused weird behavior,
  1702.     with the selected node suddenly changing to whatever was under the mouse
  1703.     cursor (or AV-ing if the mouse cursor wasn't over the DUnit form) when
  1704.     the user executed one of the keyboard shortcuts.
  1705.     It was intermittent most likely because the ShortCuts belonged to
  1706.     Main Menu items as well (shared from the Action.ShortCut), and the bug
  1707.     dependended on the Popup menu items receiving the ShortCut Windows message
  1708.     first.
  1709.     This code ensures that node selection occurs prior to the popup menu
  1710.     appearing when the user right-clicks on a non-selected tree node. }
  1711.   if (Button = mbRight) and (htOnItem in TestTree.GetHitTestInfoAt(X, Y)) then
  1712.   begin
  1713.     NewNode := TestTree.GetNodeAt(X, Y);
  1714.     if TestTree.Selected <> NewNode then
  1715.       TestTree.Selected := NewNode;
  1716.   end;
  1717. end;
  1718. procedure TGUITestRunner.GoToNextSelectedTestActionExecute(
  1719.   Sender: TObject);
  1720. var
  1721.   aNode: TTreeNode;
  1722. begin
  1723.   if TestTree.Selected <> nil then
  1724.   begin
  1725.     aNode := TestTree.Selected.GetNext;
  1726.     while aNode <> nil do
  1727.     begin
  1728.       if SelectNodeIfTestEnabled(aNode) then
  1729.         break
  1730.       else
  1731.         aNode := aNode.GetNext;
  1732.     end;
  1733.   end;
  1734. end;
  1735. function TGUITestRunner.SelectNodeIfTestEnabled(ANode: TTreeNode): boolean;
  1736. var
  1737.   ATest: ITest;
  1738. begin
  1739.   ATest := NodeToTest(ANode);
  1740.   if (ATest.Enabled) and (IsTestMethod(ATest)) then
  1741.   begin
  1742.     Result := true;
  1743.     SelectNode(ANode);
  1744.   end
  1745.   else
  1746.     Result := false;
  1747. end;
  1748. procedure TGUITestRunner.GoToPrevSelectedTestActionExecute(
  1749.   Sender: TObject);
  1750. var
  1751.   aNode: TTreeNode;
  1752. begin
  1753.   if TestTree.Selected <> nil then
  1754.   begin
  1755.     aNode := TestTree.Selected.GetPrev;
  1756.     while aNode <> nil do
  1757.     begin
  1758.       if SelectNodeIfTestEnabled(aNode) then
  1759.         break
  1760.       else
  1761.         aNode := aNode.GetPrev;
  1762.     end;
  1763.   end;
  1764. end;
  1765. procedure TGUITestRunner.SelectNode(node: TTreeNode);
  1766. begin
  1767.   node.Selected := true;
  1768.   MakeNodeVisible(node);
  1769. end;
  1770. procedure TGUITestRunner.SetupCustomShortcuts;
  1771. begin
  1772.   { the following shortcuts are not offered as an option in the
  1773.     form designer, but can be set up here }
  1774.   GoToNextSelectedTestAction.ShortCut := ShortCut(VK_RIGHT, [ssCtrl]);
  1775.   GoToPrevSelectedTestAction.ShortCut := ShortCut(VK_LEFT, [ssCtrl]);
  1776. end;
  1777. procedure TGUITestRunner.SetupGUINodes;
  1778. var
  1779.   node: TTreeNode;
  1780.   test: ITest;
  1781. begin
  1782.   { Set up the GUI nodes in the test nodes. We do it here because the form,
  1783.     the tree and all its tree nodes get recreated in TCustomForm.ShowModal
  1784.     in D8+ so we cannot do it sooner.
  1785.     This method is also called after loading test libraries }
  1786.   node := TestTree.Items.GetFirstNode;
  1787.   while assigned(node) do
  1788.   begin
  1789.     // Get and check the test for the tree node
  1790.     test := NodeToTest(node);
  1791.     assert(Assigned(test));
  1792.     // Save the tree node in the test and get the next tree node
  1793.     test.GUIObject := node;
  1794.     node := node.GetNext;
  1795.   end;
  1796. end;
  1797. const
  1798.   PopupTitle   = 'TestCase Run-Time Applied Properties';
  1799.   PopupPrevious= ' Previous';
  1800.   PopupRun     = ' Run Selected Test';
  1801.   PopupNext    = ' Next';
  1802.   NoChecksStrT = ' FailsOnNoChecksExecuted  := True ';
  1803.   NoChecksStrF = ' FailsOnNoChecksExecuted  := False';
  1804.   MemLeakStrT  = ' FailsOnMemoryLeak        := True ';
  1805.   MemLeakStrF  = ' FailsOnMemoryLeak        := False';
  1806.   MemGainStrT  = ' FailsOnMemoryRecovery    := True ';
  1807.   MemGainStrF  = ' FailsOnMemoryRecovery    := False';
  1808.   MemBytesStr0 = ' AllowedMemoryLeakSize '           ;
  1809.   IgnoreStrT   = ' IgnoreSetUpTearDownLeaks := True ';
  1810.   IgnoreStrF   = ' IgnoreSetUpTearDownLeaks := False';
  1811. procedure TGUITestRunner.TestCasePropertiesActionExecute(Sender: TObject);
  1812. var
  1813.   aNode: TTreeNode;
  1814.   ATest: ITest;
  1815. begin
  1816.   if TestTree.Selected <> nil then
  1817.   begin
  1818.     aNode := TestTree.Selected;
  1819.     if (aNode <> nil) then
  1820.     begin
  1821.       ATest := NodeToTest(ANode);
  1822.       if IsTestMethod(ATest) then
  1823.       begin
  1824.         if ATest.FailsOnNoChecksExecuted then
  1825.           FNoChecksStr := NoChecksStrT
  1826.         else
  1827.           FNoChecksStr := NoChecksStrF;
  1828.         fNoCheckExecutedPtyOverridden := FailIfNoChecksExecutedAction.Checked and
  1829.           (not ATest.FailsOnNoChecksExecuted);
  1830.         if ATest.FailsOnMemoryLeak then
  1831.           FMemLeakStr := MemLeakStrT
  1832.         else
  1833.           FMemLeakStr := MemLeakStrF;
  1834.         fMemLeakDetectedPtyOverridden := FailTestCaseIfMemoryLeakedAction.Checked and
  1835.           (not ATest.FailsOnMemoryLeak);
  1836.         if (ATest.FailsOnMemoryLeak and ATest.FailsOnMemoryRecovery) then
  1837.           FMemGainStr := MemGainStrT
  1838.         else
  1839.           FMemGainStr := MemGainStrF;
  1840.         if (ATest.IgnoreSetUpTearDownLeaks) and ATest.FailsOnMemoryLeak then
  1841.           FIgnoreLeakStr := IgnoreStrT
  1842.         else
  1843.           FIgnoreLeakStr := IgnoreStrF;
  1844.         FIgnoreSetUpTearDownLeakPtyOverridden := ATest.IgnoreSetUpTearDownLeaks and
  1845.           ATest.FailsOnMemoryLeak and (not IgnoreMemoryLeakInSetUpTearDownAction.Checked);
  1846.         FBytes := ':= ' + IntToStr(Atest.AllowedMemoryLeakSize) + ' Bytes';
  1847.         FMemBytesStr := MemBytesStr0 + FBytes;
  1848.         TestCaseProperty.Popup(Self.Left + FPopupX,Self.Top + FPopupY);
  1849.       end;
  1850.     end;
  1851.     ATest := nil;
  1852.   end;
  1853. end;
  1854. procedure TGUITestRunner.Previous1Click(Sender: TObject);
  1855. begin
  1856.   GoToPrevSelectedTestActionExecute(Self);
  1857.   TestCasePropertiesActionExecute(self);
  1858. end;
  1859. procedure TGUITestRunner.Next1Click(Sender: TObject);
  1860. begin
  1861.   GoToNextSelectedTestActionExecute(Self);
  1862.   TestCasePropertiesActionExecute(self);
  1863. end;
  1864. procedure TGUITestRunner.TestCasePropertiesMeasureItem(Sender: TObject;
  1865.   ACanvas: TCanvas; var Width, Height: Integer);
  1866. var
  1867.   ImageSize: TSize;
  1868. begin
  1869.   if GetTextExtentPoint32(ACanvas.Handle,
  1870.                           PChar(PopupTitle),
  1871.                           Length(PopupTitle),
  1872.                           ImageSize) then
  1873.   begin
  1874.     Width  := ImageSize.cx + 60;
  1875.     Height := ImageSize.cy + 4;
  1876.   end;
  1877. end;
  1878. procedure TGUITestRunner.MenuLooksInactive(ACanvas: TCanvas;
  1879.                                            ARect: TRect;
  1880.                                            Selected: Boolean;
  1881.                                            ATitle: string;
  1882.                                            TitlePosn: UINT;
  1883.                                            PtyOveridesGUI: boolean);
  1884. var
  1885.   Count: integer;
  1886.   SecondPart: string;
  1887.   SecondRect: TRect;
  1888. begin
  1889.   if TitlePosn = DT_CENTER then
  1890.     ACanvas.Font.Style := [fsBold];
  1891.   if Selected then
  1892.     ACanvas.Font.Color := clBlack;
  1893.   if PtyOveridesGUI then
  1894.     ACanvas.Brush.Color := clYellow
  1895.   else
  1896.     ACanvas.Brush.Color := TColor($C0FCC0);  //Sort of Moneygreen
  1897.   ACanvas.FillRect(ARect);
  1898.   Count := Pos(':=', ATitle);
  1899.   if Count = 0 then
  1900.     DrawText(ACanvas.Handle,
  1901.              PChar(ATitle),
  1902.              Length(ATitle),
  1903.              ARect,
  1904.              DT_VCENTER or DT_SINGLELINE or DT_NOCLIP or DT_NOPREFIX or TitlePosn)
  1905.   else
  1906.   begin
  1907.     DrawText(ACanvas.Handle,
  1908.              PChar(ATitle),
  1909.              Count-1,
  1910.              ARect,
  1911.              DT_VCENTER or DT_SINGLELINE or DT_NOCLIP or DT_NOPREFIX or TitlePosn);
  1912.     SecondPart := Copy(ATitle, Count, Length(ATitle));
  1913.     SecondRect := ARect;
  1914.     SecondRect.Left := 5 * ((ARect.Right - ARect.Left) div 8);
  1915.     DrawText(ACanvas.Handle,
  1916.              PChar(SecondPart),
  1917.              Length(SecondPart),
  1918.              SecondRect,
  1919.              DT_VCENTER or DT_SINGLELINE or DT_NOCLIP or DT_NOPREFIX or TitlePosn)
  1920.   end;
  1921. end;
  1922. procedure TGUITestRunner.MenuLooksActive(ACanvas: TCanvas;
  1923.                                          ARect: TRect;
  1924.                                          Selected: Boolean;
  1925.                                          ATitle: string;
  1926.                                          TitlePosn: UINT);
  1927. begin
  1928.   ACanvas.FillRect(ARect);
  1929.   DrawText(ACanvas.Handle,
  1930.            PChar(ATitle),
  1931.            Length(ATitle),
  1932.            ARect,
  1933.            DT_VCENTER or DT_SINGLELINE or DT_NOCLIP or DT_NOPREFIX or TitlePosn);
  1934. end;
  1935. procedure TGUITestRunner.TestCasePropertiesDrawItem(Sender: TObject;
  1936.   ACanvas: TCanvas; ARect: TRect; Selected: Boolean);
  1937. begin
  1938.   MenuLooksInactive(ACanvas, ARect, Selected, PopupTitle, DT_CENTER, False);
  1939. end;
  1940. procedure TGUITestRunner.Previous1DrawItem(Sender: TObject;
  1941.   ACanvas: TCanvas; ARect: TRect; Selected: Boolean);
  1942. begin
  1943.   MenuLooksActive(ACanvas, ARect, Selected, PopupPrevious, DT_LEFT);
  1944. end;
  1945. procedure TGUITestRunner.RunSelectedTest1DrawItem(Sender: TObject;
  1946.   ACanvas: TCanvas; ARect: TRect; Selected: Boolean);
  1947. begin
  1948.   MenuLooksActive(ACanvas, ARect, Selected, PopupRun, DT_LEFT);
  1949. end;
  1950. procedure TGUITestRunner.Next1DrawItem(Sender: TObject; ACanvas: TCanvas;
  1951.   ARect: TRect; Selected: Boolean);
  1952. begin
  1953.   MenuLooksActive(ACanvas, ARect, Selected, PopupNext, DT_LEFT);
  1954. end;
  1955. procedure TGUITestRunner.FailNoCheckExecutedMenuItemDrawItem(
  1956.   Sender: TObject; ACanvas: TCanvas; ARect: TRect; Selected: Boolean);
  1957. begin
  1958.   MenuLooksInactive(ACanvas, ARect, Selected, FNoChecksStr,
  1959.     DT_LEFT, fNoCheckExecutedPtyOverridden);
  1960. end;
  1961. procedure TGUITestRunner.FailsOnMemoryLeakMenuItemDrawItem(Sender: TObject;
  1962.   ACanvas: TCanvas; ARect: TRect; Selected: Boolean);
  1963. begin
  1964.   MenuLooksInactive(ACanvas, ARect, Selected, FMemLeakStr,
  1965.     DT_LEFT, fMemLeakDetectedPtyOverridden);
  1966. end;
  1967. procedure TGUITestRunner.FailsOnMemoryRecoveryMenuItemDrawItem(
  1968.   Sender: TObject; ACanvas: TCanvas; ARect: TRect; Selected: Boolean);
  1969. begin
  1970.   MenuLooksInactive(ACanvas, ARect, Selected, FMemGainStr,
  1971.     DT_LEFT, False);
  1972. end;
  1973. procedure TGUITestRunner.AllowedLeakSizeMemuItemDrawItem(Sender: TObject;
  1974.   ACanvas: TCanvas; ARect: TRect; Selected: Boolean);
  1975. begin
  1976.   MenuLooksInactive(ACanvas, ARect, Selected, FMemBytesStr, DT_LEFT, False);
  1977. end;
  1978. procedure TGUITestRunner.TestCaseIgnoreSetUpTearDownLeaksMenuItemDrawItem(
  1979.   Sender: TObject; ACanvas: TCanvas; ARect: TRect; Selected: Boolean);
  1980. begin
  1981.   MenuLooksInactive(ACanvas, ARect, Selected, FIgnoreLeakStr,
  1982.     DT_LEFT, FIgnoreSetUpTearDownLeakPtyOverridden);
  1983. end;
  1984. procedure TGUITestRunner.pmTestTreePopup(Sender: TObject);
  1985. var
  1986.   aNode: TTreeNode;
  1987.   ATest: ITest;
  1988. begin
  1989.   if TestTree.Selected <> nil then
  1990.   begin
  1991.     aNode := TestTree.Selected;
  1992.     if (aNode <> nil) then
  1993.     begin
  1994.       ATest := NodeToTest(ANode);
  1995.       TestCasePopup.Enabled := IsTestMethod(ATest);
  1996.     end;
  1997.     ATest := nil;
  1998.   end;
  1999. end;
  2000. function TGUITestRunner.GetPropertyName(const Caption: string): string;
  2001. var
  2002.   TempStr: string;
  2003.   PosSpace: integer;
  2004. begin
  2005.   TempStr := Trim(Caption);
  2006.   PosSpace := Pos(' ',TempStr);
  2007.   if (PosSpace > 1)  then
  2008.     result := Copy(TempStr, 1, PosSpace-1);
  2009. end;
  2010. procedure TGUITestRunner.FailNoCheckExecutedMenuItemClick(Sender: TObject);
  2011. begin
  2012.   Clipboard.AsText := GetPropertyName(NoChecksStrT);
  2013. end;
  2014. procedure TGUITestRunner.FailsOnMemoryLeakMenuItemClick(Sender: TObject);
  2015. begin
  2016.   Clipboard.AsText := GetPropertyName(MemLeakStrT);
  2017. end;
  2018. procedure TGUITestRunner.AllowedLeakSizeMemuItemClick(Sender: TObject);
  2019. begin
  2020.   Clipboard.AsText := GetPropertyName(MemBytesStr0);
  2021. end;
  2022. procedure TGUITestRunner.FailsOnMemoryRecoveryMenuItemClick(
  2023.   Sender: TObject);
  2024. begin
  2025.   Clipboard.AsText := GetPropertyName(MemGainStrT);
  2026. end;
  2027. procedure TGUITestRunner.TestCaseIgnoreSetUpTearDownLeaksMenuItemClick(
  2028.   Sender: TObject);
  2029. begin
  2030.   Clipboard.AsText := GetPropertyName(IgnoreStrT);
  2031. end;
  2032. procedure TGUITestRunner.RunSelectedTestAltActionExecute(Sender: TObject);
  2033. begin
  2034.   RunSelectedTestActionExecute(Self);
  2035.   TestCasePropertiesActionExecute(Self);
  2036. end;
  2037. procedure TGUITestRunner.IgnoreMemoryLeakInSetUpTearDownActionExecute(
  2038.   Sender: TObject);
  2039. begin
  2040.   with IgnoreMemoryLeakInSetUpTearDownAction do
  2041.     Checked := not Checked;
  2042. end;
  2043. procedure TGUITestRunner.ReportMemoryLeakTypeOnShutdownActionExecute(
  2044.   Sender: TObject);
  2045. begin
  2046.   with ReportMemoryLeakTypeOnShutdownAction do
  2047.   begin
  2048.     Checked := not Checked;
  2049.   {$IFDEF VER180}
  2050.     ReportMemoryLeaksOnShutdown := Checked;
  2051.   {$ELSE}
  2052.     {$IFDEF FASTMM}
  2053.      {$IFDEF ManualLeakReportingControl}
  2054.        ReportMemoryLeaksOnShutdown := Checked;
  2055.      {$ENDIF}
  2056.     {$ENDIF}
  2057.   {$ENDIF}
  2058.   end;    // with
  2059. end;
  2060. end.